Article directory
- thread safety
-
- 1. What is a thread safety issue
- 2. Thread unsafe instance
- Three, thread unsafe reasons to solve
-
- 1. Atomicity
-
- 1.1 Definition
- 1.2 Reasons for insecurity
- 1.3 synchronized keyword
- 1.4 synchronized feature
- 1.5 synchronized use
- 1.6 Modification example
- 2. Memory visibility
-
- 1.1 Example
- 1.2 Reasons for insecurity
- 1.3 volatile keyword
- 1.4 Modified example
- 3 Instruction reordering
-
- 1.1 Function
- 1.2 Example
- Summarize
Thread Safety
1. What is thread safety issue
First of all, we need to understand that the scheduling of threads in the operating system is preemptive, or random, which causes the execution order of threads during thread scheduling execution to be uncertain, and some code execution orders do not affect the results of program running. , but there are also some codes whose execution order changes, and the rewritten running results will be affected, which will cause bugs in the program. The code that will cause bugs in the program when multiple threads are concurrent is called thread-unsafe code, which is thread Security Question.
Second, thread unsafe example
public class ThreadDemo9 {<!-- --> public static void main(String[] args) throws InterruptedException {<!-- --> Counter counter = new Counter(); Thread t1 = new Thread(() -> {<!-- --> for (int i = 0; i < 50000; i ++ ) {<!-- --> counter. add(); } }); Thread t2 = new Thread(() -> {<!-- --> for (int i = 0; i < 50000; i ++ ) {<!-- --> counter. add(); } }); t1. start(); t2.start(); t1. join(); t2. join(); System.out.println(counter.get()); } } class Counter {<!-- --> private int count = 0; public void add() {<!-- --> count + + ; } public int get() {<!-- --> return count; } }
Expected result: 100000
actual results:
Why are the two threads incremented 5w times respectively, but the result is not 10w?
Three, thread unsafe reasons to solve
1. Atomicity
1.1 Definition
A group of operations (one or more lines of code) is the ****indivisible minimum execution unit*, which means that this group of operations is *atomic** **of
*Multiple threads concurrently *operate on a * shared variable* , the operation will be /strong>*not atomic*
1.2 Reasons for insecurity
counter.add() We can split this sentence into 3 operations:
- load reads a value from memory into a register
- add for self-increment operation
- save writes from registers back to memory
Due to the randomness of thread execution, there may be interleaved execution of these three steps (one is adding, the other is loading)
If we fix the three-step operation together through code, we can solve the problem
1.3 synchronized keyword
When you use an ATM in your room, you lock the door so no one else can come in
After you are done using the room, unlock it, and other people can enter the room at this time
The most commonly used locking operation in java is to use the synchronized
keyword to lock
1.4 synchronized feature
Mutual exclusion
- Enter the code block modified by synchronized, which is equivalent to locking
- Exit the synchronized modified code block, which is equivalent to unlock
- The thread that has not grabbed the lock blocks and waits to participate in the next ‘lock competition’
- Lock contention
- Two threads compete for the same lock, resulting in blocking wait
- Two threads compete for different locks, and there will be no blocking wait
Refresh memory
The working process of synchronized:
- acquire a mutex
- Copy the latest variable from main memory to working memory
- perform operations on variables
- Flush the value of the modified shared variable to main memory
- release the mutex
Reentrant
synchronized is a reentrant lock
The same thread can successfully apply for an object lock multiple times
After a thread requests successfully, the JVM will record the thread holding the lock, and set the counter to 1; at this time, other threads request the lock, they must wait; and if the thread holding the lock requests the lock again lock, you can get the lock again, and the counter will increase at the same time; when the thread exits the synchronization code block, the counter will decrement, and if the counter is 0, the lock will be released.
1.5 synchronized use
- Decorate common methods
public class SynchronizedDemo {
synchronized public void method() {? }
}
- Modified code block
public class SynchronizedDemo {
? public void method() {
synchronized (**this**) { }? }
}
Here this can be replaced with any Object class object, the effect is the same as that of ordinary decoration
- Decorate static methods
public class SynchronizedDemo {
synchronized public static void method() {? }
}
- Modified code block
public class SynchronizedDemo {
public void method() { synchronized (**SynchronizedDemo. class**) { }? }
}
- lock object
Whoever calls the method or class modified by synchronized is the lock object
The counter here is calling the add method, and the counter is the lock object
1.6 Modification example
public void add() {<!-- --> synchronized(this){<!-- --> count + + ; } }
Ensure that the three-step operations in counter.add() are executed at the same time, so that the final result can be correct.
The difference between join and lock:
- join: let a certain thread complete execution, complete serial, low efficiency
- Locking: some parts are serial, others are parallel
- Under the premise of ensuring thread safety, the efficiency is higher.
2. Memory visibility
1.1 Example
public static int flag = 0; public static void main(String[] args) {<!-- --> Thread t1 = new Thread(() -> {<!-- --> while (flag == 0) {<!-- --> // empty } System.out.println("Loop end! t1 end!"); }); Thread t2 = new Thread(() -> {<!-- --> Scanner scanner = new Scanner(System.in); System.out.println("Please enter an integer: "); flag = scanner. nextInt(); }); t1. start(); t2.start(); }
As can be seen from the execution results, the program does not end after we enter a number.
1.2 Reasons for insecurity
The main two steps performed by the program
- load reads data from memory into a register
- Whether the value of the cmp compare register is 0
Since the body of the while loop is empty, the execution speed is very fast, far exceeding the speed of comparison, so that the value read out each time is 0, so the compiler actively optimizes, thinking that load reads It will only be 0 when it comes out, which will result in reading data only once, and the comparison will be carried out afterwards. This is why even if we enter a non-zero number, the program cannot be stopped
Compiler optimization
Under the premise of ensuring that the result of the program remains unchanged (multi-threading is not necessarily the case), the efficiency of the program is improved through operations such as addition and subtraction statements.
To solve this problem, we only need to let the compiler not actively optimize
1.3 volatile keyword
Let the compiler not optimize the variable it decorates, and re-read it from memory every time
- volatile does not guarantee atomicity
- One thread reads and one thread writes.
Working memory: registers + cache
expand:
-
CPU cache: read speed is between read register and memory
-
cpu read data sequence: register = “cache 1 = “cache 2 = “cache 3 = “memory
1.4 Modification example
public class ThreadDemo14 {<!-- --> volatile public static int flag = 0; public static void main(String[] args) {<!-- --> Thread t1 = new Thread(() -> {<!-- --> while (flag == 0) {<!-- --> // empty } System.out.println("Loop end! t1 end!"); }); Thread t2 = new Thread(() -> {<!-- --> Scanner scanner = new Scanner(System.in); System.out.println("Please enter an integer: "); flag = scanner. nextInt(); }); t1. start(); t2.start(); } }
3 command reordering
1.1 Function
Instruction reordering: On the premise of keeping the overall logic unchanged, adjust the code execution order to improve efficiency.
1.2 Example
adjusted:
Summary
Reasons for thread insecurity:
Threads are preemptively executed, and the scheduling between threads is full of randomness
Multiple threads modify the same variable
Operations on variables are not atomic
Thread safety due to memory visibility
Instruction reordering also affects thread safety