In Java thread concurrency processing, there is a great deal of confusion about the use of a keyword volatile, thinking that by using this keyword, you can do everything in parallel with multithreading.
The Java language supports multithreading, in order to solve the problem of thread concurrency, the synchronization block and volatile keyword mechanism are introduced into the language.
Synchronized
Synchronized block Everyone is more familiar with the Synchronized keyword to achieve, all add synchronized and block statements, in multi-threaded access, at the same time only one thread can use synchronized modified method or code block.
Volatile
A variable decorated with volatile, the thread reads the variable's most-modified value each time it uses the variable. Volatile are easily misused for atomic manipulation.
Here's an example where we implement a counter that invokes the Counter Inc method each time the thread starts, adding a
Execution Environment--JDK version: jdk1.6.0_31, Memory: 3G cpu:x86 2.4G
Copy Code code as follows:
public class Counter {
public static int count = 0;
public static Void Inc () {
This delay is 1 milliseconds, 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 to see the actual results
for (int i = 0; i < 1000; i++) {
New Thread (New Runnable () {
@Override
public void Run () {
Counter.inc ();
}
). Start ();
}
Each run here may be a different value, possibly 1000.
SYSTEM.OUT.PRINTLN ("Operation Result: counter.count=" + counter.count);
}
}
Run Result: counter.count=995
The results of the actual operation may be different every time, the results of this machine: the results: counter.count=995, you can see that in a multi-threaded environment, Counter.count did not expect the result is 1000
Many people think that this is a multithreaded concurrency problem, only need to add volatile before the variable count can avoid this problem, then we modify the code to see if the results are not in line with our expectations
Copy Code code as follows:
public class Counter {
public volatile static int count = 0;
public static Void Inc () {
This delay is 1 milliseconds, 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 to see the actual results
for (int i = 0; i < 1000; i++) {
New Thread (New Runnable () {
@Override
public void Run () {
Counter.inc ();
}
). Start ();
}
Each run here may be a different value, possibly 1000.
SYSTEM.OUT.PRINTLN ("Operation Result: counter.count=" + counter.count);
}
}
Run Result: counter.count=992
The results of the operation is still not 1000 of our expectations, the following we analyze the reasons
In the context of Java garbage collection, the allocation of memory at the time of the JVM runtime is described. One of the memory areas is the JVM virtual machine stack, each thread running with a line stacks, the line stacks saved the thread run-time variable value information. When a thread accesses a value for an object, first, the value of the variable in the heap memory is found by the reference of the object, then the concrete value of the heap memory variable is load into the thread local memory, a copy of the variable is established, and then the thread no longer has any relationship with the object in the heap memory variable value, but modifies the copy 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's variable in the heap. This makes the value of the object in the heap change. A picture below
Describe this write interaction
Read and load copy variables from main memory to current working memory
Use and assign execute code to change shared variable values
Store and write use working memory data to refresh main memory related content
Where use and assign can occur multiple times
But these operations are not atomic, that is, after read load, if the main memory count variable has been modified, the value in the thread's working memory will not produce a corresponding change because it has been loaded, so the calculated result is not the same as expected
For volatile-decorated variables, the JVM virtual machine only guarantees that the values loaded from main memory to the working memory of the thread are up to date
For example, if thread 1, thread 2, finds that the value of count in main memory is 5 in the read,load operation, the newest value is loaded
After the thread 1 heap count is modified, it is write into main memory, and the count variable in main memory becomes 6
Thread 2 because the read,load operation has already been performed, the variable value of the main memory count is also updated after the operation is 6
When two threads are modified with the volatile keyword in a timely manner, concurrency is still present.