Read for about 3 minutes

Introduction: I have only read articles about volatile, and my understanding of volatile is only theoretical. Recently, I used concurrency technology in my project, so I decided to study the knowledge of Java concurrency in depth. The web is full of articles on volatile, but not in great detail. (If anyone has good information, please share it with me!) Most of them are theoretical explanations. There is no actual example code, and even if there is code, there is no test effect. In short, the theory always does not match the code.

Later in my unremitting efforts to finally research some results, here to share with you! If you find any mistakes, please correct them. Thank you!

In Java thread concurrency, there is a lot of confusion about the use of the keyword volatile, which is supposed to be all right when it comes to multithreaded concurrency.


Java language supports multithreading. In order to solve the problem of thread concurrency, synchronized and volatile keyword mechanisms are introduced into the language.

Synchronized (without much explanation)

Everyone is familiar with the synchronized keyword to achieve, all coupled with synchronized and block statements, in multi-threaded access, only one thread can use at the same time

A synchronized modified method or block of code.

volatile

For volatile variables, each time the thread uses the variable, it reads the variable’s most changed value. Volatile can easily be misused for atomic operations.

To understand the significance of the volatile keyword, you must first understand how the JVM allocates memory at runtime.

In the Java Garbage Collection collation article, the allocation of JVM runtime memory is described. One area of memory is the JVM virtual machine stack, where each thread runs on a thread stack,

The thread stack holds the thread runtime variable value information. When a thread accesses the value of an object, it first finds the value of the variable in the heap by reference to the object, and then puts the value in the heap

The value of the variable is loaded into the thread’s local memory, a copy of the variable is created, and the thread no longer has anything to do with the value of the variable in the heap, but directly modifies the value of 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 in the heap variable. This changes the value of the object in the heap. Here’s a picture

Describe this write interaction!

Now that we’ve looked at how the JVM allocates memory at runtime, let’s really dive into the specifics of volatile

Look at the code:

public class VolatileTest extends Thread {

    boolean flag = false;
    int i = 0;

    public void run(a) {
        while (!flag) {
            i++;
        }
    }

    public static void main(String[] args) throws Exception {
        VolatileTest vt = new VolatileTest();
        vt.start();
        Thread.sleep(2000);
        vt.flag = true;
        System.out.println("stope"+ vt.i); }}Copy the code

The above code is an example of controlling the VolatileTest thread while loop exit by flag!

Let me describe our program in pseudocode

  1. First create VolatileTest vt = new VolatileTest();
  2. Vt. Start ();
  3. Pause Main Thread for 2 seconds (Main) thread. sleep(2000);
  4. At this point the vt thread has started executing, doing i++;
  5. Vt. Flag = true;
  6. Println (“stope” + vt. I); Meanwhile, since vt. Flag is set to true, the VT thread makes the next while judgment while (! Flag) returns false end loop vt thread method end exit!
  7. End of main thread

There seems to be nothing wrong with the above statement, which “seems” to be completely correct. So let’s run the program and see what happens, mian. After 2 seconds, the console prints stopE-202753974.

But something strange happened and the program didn’t quit. Vt thread is still running, which means we set vt. Flag = true on the main thread. It didn’t work.

Here I need to note that some students may test the above code when the program can exit normally. That’s because your JVM is not optimized! Type Java -version under DOC to see if Java HotSpot(TM) is displayed… Server is optimized by the JVM.

If Java HotSpot(TM) is displayed… The Client mode is the Client mode. You need to set it to the Server mode

The question arises as to why I set vt. Flag = true in main; Vt thread still gets false for flag, right?

The above problem can be explained in terms of how the JVM allocates memory at runtime.

First, the VT thread copies the variables flag and I (line 3, line 4) from the “main memory” to the thread stack memory (thread working memory above) at runtime.

The VT thread then starts the while loop

 7         while(! flag) {8             i++;
 9         }
Copy the code

while (! Flag) is obtained from thread working memory, not from “main memory”.

i++; Put i++ in thread memory; Write the result back to main memory and repeat.

And then we’ll talk about the execution of the main thread. I’ll just point out the key points

vt.flag = true;

The main thread also copies the vt. Flag value from main memory to its own thread working memory and changes flag=true. The new value is then returned to main memory.

This explains why vt. Flag = true is set in main; The VT thread still gets false for flag. That’s because the VT thread values a flag from its own “working memory”, not from main memory!

This is also an optimization made by the JVM to provide performance. So how do we get the VT thread to force a flag to be evaluated in main memory every time it evaluates a flag? This is where the volatile keyword comes in.

Modify our code again

public class VolatileTest extends Thread {
    
    volatile boolean flag = false;
    int i = 0;
    
    public void run(a) {
        while (!flag) {
            i++;
        }
    }
    
    public static void main(String[] args) throws Exception {
        VolatileTest vt = new VolatileTest();
        vt.start();
        Thread.sleep(2000);
        vt.flag = true;
        System.out.println("stope"+ vt.i); }}Copy the code

Add the volatile keyword to flag to force the thread to use main memory each time it reads the value. Try our program, it has been normal exit.

JavaPub giants reference: www.cnblogs.com/xd502djj/p/…

From Java code, bytecode, the Jdk source code, assembly level, hardware level to the volatile of the veil: zhuanlan.zhihu.com/p/133851347