Keyword volatile can be said to be the most lightweight synchronization mechanism provided by a Java virtual machine. When a variable is defined as volatile, it will have two characteristics, the first is to ensure that the variable visibility of all threads, where the "visibility" refers to when a thread modifies the value of this variable, the new value for other threads can be immediately informed. While the normal variable cannot do this, the value of the normal variable is passed through the main memory, for example, thread a modifies the value of a normal variable, then writes back to the main memory, and another thread B reads from main memory after a write-back is completed, and the new variable value is visible to thread B.
Let's take a look at a well-known implementation of the "Double detection lock Singleton pattern":
1 Private StaticSingleton _instance;2 Public StaticSingleton getinstance () {3 if(_instance==NULL) {//First Heavy detection4 synchronized(Singleton.class) {5 if(_instance==NULL) {//Second Heavy detection6_instance=NewSingleton ();7 }8 }9 }Ten One return_instance; A}
Two questions:
Why do I need double testing?
If we are using a heavy test with a synchronous code block, we can certainly achieve the desired effect, but the performance is severely reduced. Because we only need to lock the first request, and then we just need to return the instance.
Second, is there a problem with the above procedure?
Of course there is a problem. Suppose now we have 4 threads (A, B, C, D) First pass the first layer of detection, when a thread A into the synchronization code block, the normal variable _instance write operations, but this write operation for threads B, C, D may be invisible. Because when B, C, D for the second detection, that is, B, C, D to go to the main memory to read ordinary variables, but at this time a thread in the working memory of the _instance variable changes, not necessarily updated to the main memory.
In order for thread A to read _instance's write to the B, C, D threads, the variable _instance needs to be prefixed with the volatile keyword. Because the JVM ensures that the variable that the volatile keyword modifies is written prior to (Happen-before) the read operation. In other words, the previous write operation can be reflected in the read operation. But if, after reading, the other thread has written again, and then the thread writes it back to main memory, it will cause inconsistent data, so volatile is not thread-safe.
4. Volatile keyword