In Java thread concurrency processing, there is a lot of confusion in the use of a keyword volatile. I think that using this keyword can make everything go well when using multi-threaded concurrency processing.
The Java language supports multi-threading. In order to solve the problem of thread concurrency, the synchronous block and volatile keyword mechanism are introduced inside the language.
synchronized
Everyone is familiar with synchronized blocks, and they are implemented through the synchronized keyword. With synchronized and block statements, only one thread can use them at the same time when accessing multi-threads.
synchronized Modified method or code block.
volatile
For variables modified with volatile, the thread will read the most modified value of the variable every time it uses the variable. Volatile is easily misused and used for atomic operations.
Let's see an example below. We implement a counter. Each time the thread starts, the counter inc method will be called to add one to the counter.
Execution environment - jdk version: jdk1.6.0_31, memory: 3G cpu: x86 2.4G
public class Counter {public static int count = 0;public static void inc() {//The delay here is 1 millisecond, making the result obvious try {Thread.sleep(1);} catch (InterruptedException e) {}count++;}public static void main(String[] args) {//Start 1000 threads at the same time, perform i++ calculations, and see the actual result for (int i = 0; i < 1000; i++) {new Thread(new Runnable() {@Overridepublic void run() {Counter.inc();}}).start();}//The value of each run may be different, which may be 1000System.out.println("Run result: Counter.count=" + Counter.count);}}Running result: Counter.count=995
The actual operation result may be different every time. The result of the machine is: Running result: Counter.count=995. It can be seen that in a multi-threaded environment, Count does not expect the result to be 1000.
Many people think that this is a multi-threaded concurrency problem. You only need to add volatile before the variable count to avoid this problem. Then we are modifying the code to see if the result meets our expectations.
public class Counter {public volatile static int count = 0;public static void inc() {//The delay here is 1 millisecond, making the result obvious try {Thread.sleep(1);} catch (InterruptedException e) {}count++;}public static void main(String[] args) {//Start 1000 threads at the same time, perform i++ calculations, and see the actual result for (int i = 0; i < 1000; i++) {new Thread(new Runnable() {@Overridepublic void run() {Counter.inc();}}).start();}//The value of each run may be different, which may be 1000System.out.println("Run result: Counter.count=" + Counter.count);}}Running result: Counter.count=992
The operation result is still not as 1000 as we expected. Let's analyze the reasons below
In the Java garbage collection article, the allocation of memory at the moment of jvm is described. One of the memory areas is the jvm virtual machine stack, and each thread has a thread stack when it runs.
The thread stack saves the variable value information during thread runtime. When a thread accesses a certain object's value, first find the value of the variable corresponding to the heap memory through the object's reference, and then put the heap memory
The specific value of the variable is loaded into the thread's local memory and a copy of the variable is created. After that, the thread no longer has any relationship with the object's variable value in the heap memory, but directly modify the value of the copy variable.
At a certain moment after modification (before the thread exits), the value of the thread variable copy is automatically written back to the object variable in the heap. This way the value of the object in the heap will change. The following picture
read and load Copy variables from main memory to current working memory
use and assign Execute code to change the shared variable value
store and write refresh main memory related content with working memory data
where use and assign can appear multiple times
However, these operations are not atomic, that is, after the read load, if the main memory count variable is modified, the value in the thread working memory will not cause corresponding changes since it has been loaded, so the calculated result will be different from expected.
For variables modified by volatile, the jvm virtual machine only ensures that the value loaded from main memory to thread working memory is the latest
For example, if thread 1 and thread 2 are performing read and load operations, and find that the value of count in the main memory is 5, then the latest value will be loaded
After the heap count is modified in thread 1, it will be written into the main memory, and the count variable in the main memory will become 6.
Since thread 2 has already performed the read and load operation, the variable value of the main memory count will also be updated to 6 after the operation.
This causes concurrency to occur after two threads are modified with the volatile keyword in time.
The above is the meaning of the volatile keyword in Java introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!