java volatile keywords
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 it 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 to perform i++ calculations and see the actual result for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { Counter.inc(); } }).start(); } //The value of each run here may be different, maybe 1000 System.out.println("Run result: Counter.count=" + Counter.count); }}运行结果:Counter.count= 995
实际运算结果每次可能都不一样,本机的结果为:运行结果:Counter.count= 995 ,可以看出,在多线程的环境下,Counter.count并没有期望结果是1000
Many people think that this is a multi-threaded concurrency problem. You only need to add volatile很多人以为,这个是多线程并发问题,只需要在变量count之前加上就可以避免这个问题,那我们在修改代码看看,看看结果是不是符合我们的期望
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() { @Override public void run() { Counter.inc(); } }).start(); } //The value of each run here may be different, possibly 1000 System.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
Describe this writing interaction
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.
Thank you for reading, I hope it can help you. Thank you for your support for this site!