Today, I read an article on the Internet, talking about the volatile feature to use 1000 threads constantly accumulating numbers, each time the cumulative 1, to the final value is not 1000.
The article is a bit misunderstood by others, but in the comments of the article, the author also points out the mistake.
I based on the error of the article and the comments of netizens, summed up some of their own methods and ideas. I hope to discuss with you.
Article Source: http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
The problem with this article is that 1000 threads may have n (for example, 50) threads not finished, the main thread (the main method) has been executed, so the last count value is not the value we want. Even after 1000 threads have finished executing, the main thread gets the count value, and the data is not necessarily the correct one. Because volatile does not guarantee atomicity, it can only guarantee visibility. See below for analysis.
About volatile:
Java language Specification Description: Each variable has a main memory. To ensure optimal performance, the JVM allows a thread to copy a private copy from main memory, and then reads the variable from the main memory when it is read, and when it exits, synchronizes the modified value to the main memory.
According to the article provided above, it seems to be possible to solve 1000 cumulative calculated values with volatile. But the result is not.
First of all, two concepts: atomicity and visibility
Atomicity, according to my own understanding: The current variable allows only one thread to operate and does not accept multiple threads for access. So each time is the most recent value.
Visibility, according to my own understanding: variable T. A thread modifies the value of the T variable, which is visible to the B thread. But a gets to the value of T plus 1, suddenly hangs, B gets the value is the most recent value, volatile can guarantee that B can get to the T is the most recent value, because A's t+1 is not written into the main memory. There is no problem with this logic.
Back to the above 1000 cumulative problem, the variable count,1000 times cumulative, 1000 threads, volatile can guarantee that each thread read the value of the variable is the latest in memory, this is no problem.
Within these 1000 threads, there will be a scenario like this:
When the NO. 523 thread reads the count value, assuming that the value is 522, the thread adds count to 1, Count is 523, but this time the count value is not written to the main memory, the CPU in some case the No. 523 thread aborts (hangs), so, The NO. 524 thread reads the value from main memory or 522, and when the No. 524 thread writes the value to main memory, the count value is 523, and then the NO. 523 thread starts executing (at this point the No. 523 thread has already added the value of count and the value is 523, except that it is not synchronized to main memory). Synchronize the Count value to the main memory, this time, the value of count is still 523, the NO. 524 thread accumulated value equals no accumulation. So the final data must not be 1000.
The following code is my personal understanding:
Import Java.util.concurrent.countdownlatch;import Java.util.concurrent.atomic.atomicinteger;public class Counter { public static Atomicinteger count = new Atomicinteger ();//atomic operation public static Countdownlatch latch= new Countdownlatch (1000 );//thread collaboration handles public static volatile int countnum = 0;//volatile can only guarantee visibility and cannot guarantee atomicity public static int synnum = 0;//synchronous processing Compute public static void Inc () {try {thread.sleep (1);} catch (Interruptedexception e) {}countnum++;int c = count.addandget (1); add (); System.out.println (Thread.CurrentThread (). GetName () + "------>" + C);} public static synchronized void Add () {synnum++;} public static void Main (string[] args) {//Start 1000 threads at the same time to perform i++ calculations to see actual results for (int i = 0; i <; i++) {New Thread (new Run Nable () {@Overridepublic void run () {counter.inc (); Latch.countdown ();}}, "thread" + i). Start (); try {latch.await ();} catch (Interruptedexception e) {e.printstacktrace ();} System.out.println (Thread.CurrentThread (). GetName ()); SYSTEM.OUT.PRINTLN ("Run Result: counter.count=" + count.get () + ",,, "+ countnum +",,, "+ Synnum);}
Count.get () is the value of Atomicinteger;
Count is the value of a variable modified with volatile;
Synnum is a value modified with synchronized;
So, with synchronized and atomicinteger you can guarantee that the data you want, volatile is not guaranteed.
First Run Result:
Main
Operation Result: counter.count=1000,,, 991,,, 1000
Second run Result:
Main
Operation Result: counter.count=1000,,, 998,,, 1000
Third Run Result:
Main
Operation Result: counter.count=1000,,, 993,,, 1000
Visible, even if the use of volatile, there is no guarantee that the data is the data you want, volatile can only guarantee the visibility of your data (access to the latest data, can not guarantee atomicity, plainly, volatile and atomicity do not matter)
To ensure atomicity, the accumulation of data, you can use the Atomicinteger class;
You can also use synchronized to ensure consistency of data.
We welcome the different opinions and views, and discuss and exchange together.
Volatile, synchronized, Atomicinteger multi-threaded cumulative 1000 counts difference