1. Java memory model (JMM)
Java's memory model is as follows, all variables are stored in main memory, and each thread has its own working memory.
Shared variables: If a variable is used in multiple threads, then this variable is a shared variable for these THREADS.
Visibility: A thread modifies a shared variable to be able to get to the main memory in a timely manner and let other threads see it.
How do you understand the meaning of the above visibility?
The thread changes the shared variables only in its own working memory, and cannot directly modify the shared variables in the main memory. And one thread cannot directly access the value of a variable in another thread, only shared pass through main memory.
then, when thread A is required to modify the shared variable and update it to main memory in a timely manner, thread B can get the latest value from main memory to working memory in a timely manner.
such as a shared variable int i = 0; Thread A changes it to I = 1; Other threads get the value of I at this point, and should be able to get 1 in time instead of 0.
2. Synchronized realization of visibility
Synchronized also achieves visibility in addition to the common Atomicity. This is because:
1) before the line threads unlocked, you must refresh the current value of the shared variable to the main memory;
2) when the line Cheng, the value of the shared variable in the working memory is emptied, and the most recent shared variable value is obtained from main memory when using the shared variable (lock and unlock required the same lock)
3. Volatile for visibility
Visibility is achieved through memory barriers and no reordering optimizations.
1) after the shared variable is written, a store barrier instruction is added to force the value of the shared variable to be flushed to the main memory;
2) before reading the shared variable, add a load barrier directive to force the latest value from the main memory to be flushed to the working memory;
4.volatile does not guarantee atomicity
A more typical example is the + + Operator.
In the following code, a total of 1000 threads were created and expected to be added 1000 times, so the value of number should be 1000, which might actually not be.
This is because the + + operator is not a single operation. Taking number++ as an example, it can be seen that the value of number is taken out of main memory, then added 1, the working memory is refreshed, and the main memory is refreshed, so several steps.
and volatile does not guarantee atomicity, which means that this is possible:
1) thread A Gets the value of number to main memory (assuming 10) to the working memory
2) CPU scheduling at this time, a pause, thread B start execution, also from the main memory to the number of 10,number++, number 11, flush to the main memory
3) thread A continues to execute number++, its working memory number is 10, and the execution finishes flushing to main memory, at which point the value is 11. That is, AB Two threads perform +1 operations at the same time, but the final result is only 1.
1 public classVolatiledemo {2 3 Private intNumber = 0;4 5 public voidIncrease () {6number++;7 }8 9 public intgetnumber () {Ten returnnumber ; one } a - public Static voidmain (string[] Args) { - FinalVolatiledemo demo =NewVolatiledemo (); the - for(inti = 0; I <= 999; i++) { - NewThread (NewRunnable () { - @Override + public voidRun () { - demo.increase (); + } a }). start (); at } - - //thread does not finish, the main thread yields CPU resources - while(thread.activecount () > 1){ - Thread.yield (); - } in - //until the above threads are finished, and then printed, to avoid printing not the final data to System.out.println (demo.getnumber ()); + } -}
5.volatile Applicable Scenarios
1) write operations on shared variables, independent of their previous values
inappropriate: number++, number = number * 2, number + = 1, etc.
Appropriate: Boolean value
2) the variable is not included in the invariant with other variables, that is, different volatile variables, can not be dependent on each other
6.AtomicInteger Implementation Increment
We already know that a shared variable of integral type is to be incremented, and if you use the + + operator, even with the volatile keyword, it cannot be guaranteed to be atomic. If you add a synchronized block to an access variable, or you can re-enter the lock, the overhead is too high.
After JDK1.5, you can use Atomicinteger to Increment. This class is Thread-safe.
The above code can be modified as follows to ensure atomicity and Visibility.
1 Importjava.util.concurrent.atomic.AtomicInteger;2 3 public classVolatiledemo {4 5 PrivateAtomicinteger number =NewAtomicinteger (0);6 7 public voidIncrease () {8 Number.incrementandget ();9 }Ten one public intgetnumber () { a returnNumber.intvalue (); - } - the public Static voidmain (string[] Args) { - FinalVolatiledemo demo =NewVolatiledemo (); - - for(inti = 0; I <= 999; i++) { + NewThread (NewRunnable () { - @Override + public voidRun () { a demo.increase (); at } - }). start (); - } - - //thread does not finish, the main thread yields CPU resources - while(thread.activecount () > 1){ in Thread.yield (); - } to + //until the above threads are finished, and then printed, to avoid printing not the final data - System.out.println (demo.getnumber ()); the } *}
"web Learning notes" The visibility and atomicity of Java shared variables