meaning of the volatile keyword in Java
In Java thread concurrency processing, there is a very big confusion about the use of a keyword volatile, for the use of this keyword, in the multi-threaded concurrent processing can be all right.
The Java language is multi-threaded, and in order to solve the problem of thread concurrency, the synchronization block and the volatile keyword mechanism are introduced inside the language.
synchronized
Synchronization block Everyone is more familiar with the Synchronized keyword to achieve, all plus synchronized and block statements, in multi-threaded access, at the same time only one thread can be used
Synchronized a modified method or block of code.
Volatile
With volatile modifiers, the thread will read the variable's most-modified value each time it uses the variable. Volatile is easily misused and used for atomic operations.
Here is an example, we implement a counter, each time the thread starts, the Counter Inc method is called, the counter is added a
Execution Environment--JDK version: jdk1.6.0_31, Memory: 3G cpu:x86 2.4G
1234567891011121314151617181920212223242526272829303132 |
public class Counter {
public static int count =
0
;
public static void inc() {
//这里延迟1毫秒,使得结果明显
try {
Thread.sleep(
1
);
}
catch (InterruptedException e) {
}
count++;
}
public static void main(String[] args) {
//同时启动1000个线程,去进行i++计算,看看实际结果
for (
int i =
0
; i <
1000
; i++) {
new Thread(
new Runnable() {
@Override
public void run() {
Counter.inc();
}
}).start();
}
//这里每次运行的值都有可能不同,可能为1000
System.out.println(
"运行结果:Counter.count=" + Counter.count);
}
}
|
1 |
实际运算结果每次可能都不一样,本机的结果为:运行结果:Counter.count= 995 ,可以看出,在多线程的环境下,Counter.count并没有期望结果是 1000 |
1 |
很多人以为,这个是多线程并发问题,只需要在变量count之前加上 volatile 就可以避免这个问题,那我们在修改代码看看,看看结果是不是符合我们的期望 |
1234567891011121314151617181920212223242526272829303132 |
public class Counter {
public volatile static int count =
0
;
public static void inc() {
//这里延迟1毫秒,使得结果明显
try {
Thread.sleep(
1
);
}
catch (InterruptedException e) {
}
count++;
}
public static void main(String[] args) {
//同时启动1000个线程,去进行i++计算,看看实际结果
for (
int i =
0
; i <
1000
; i++) {
new Thread(
new Runnable() {
@Override
public void run() {
Counter.inc();
}
}).start();
}
//这里每次运行的值都有可能不同,可能为1000
System.out.println(
"运行结果:Counter.count=" + Counter.count);
}
}
|
Running Result: counter.count=992
The results of the operation is still not what we expected 1000, let us analyze the reasons below
In the Java garbage collection article, the allocation of memory at runtime of the JVM is described. One of the memory areas is the JVM virtual machine stack, and each thread runs with a line stacks,
Line stacks saves the variable value information when the thread runs. When a thread accesses an object, the value of the variable that corresponds to the heap memory is first found by the object's reference, and then the heap memory
The specific value of the variable is load into the thread's local memory, a copy of the variable is created, and then the thread is no longer related to the object in the heap memory variable value, but directly modifies the value of the replica variable.
At some point after the modification (before the thread exits), the value of the thread variable copy is automatically written back to the object in the heap variable. This changes the value of the object in the heap. Here is a picture
Describe this write interaction
Read and load copy variables from main memory to current working RAM
Use and assign execute code, change shared variable value
Store and write refresh main memory related content with work-in-RAM data
Where use and assign can appear multiple times
However, these operations are not atomic, that is, after read load, if the main memory count variable is modified, the value in the thread's working memory will not change because it has been loaded, so the computed result will not be the same as expected
For volatile-modified variables, the JVM virtual machine simply guarantees that the value from main memory load to the working memory of the thread is up-to-date
For example, if thread 1, thread 2 in the read,load operation, found that the value of count in main memory is 5, then the latest value will be loaded
After the thread 1 heap count is modified, it is write to main memory, and the count variable in main memory becomes 6
Thread 2 because the read,load operation has been performed, after the operation, the main memory will also be updated count of the variable value of 6
When two threads are modified with the volatile keyword in a timely manner, there is still a concurrency situation.
Meaning of the volatile keyword in Java