The question about volatile

public class TestThread {
  private static int  = 0;
  private volatile static int volatile = 0;

  public static void main(String[] args) {
    new Thread(){
      public void run(){
        System.out.println("");
        while(==0&&volatile ==0){
          //System.out.println("12312321312312321");
        }
        System.out.println("");
        System.exit(0);
      }
    }.start();

    new Thread(){
      public void run(){
          try {
            Thread.sleep(1500);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        System.out.println("");
           = 1;
      }
    }.start();
  }
}

Program output:



ends normally

but if you remove the volatile modifier from the volatile variable, the program will loop.

the guess I can give now is that when jmm gets the volatile variable, it will also refresh the value of the non-volatile variable?

I hope the concurrency god can help answer this question

Mar.28,2021

this is related to the cache invalidation mechanism of the hardware. To put it simply, cache invalidation is done by line, not by variable. Because the definitions of the two variables are very close, they are likely to be together in memory / cache. This causes volatile variables to expire together with normal variables when the cache is invalidated.


Hello, the above problems lead to the invisibility of shared variables under concurrency. Both synchronized and volatile are designed to protect the safety of multithreads. Synchronized has atomicity and visibility, while volatile has only visibility. The reason for the above acceptance loop is that there is thread crossover, and volatile cannot guarantee atomicity. The visibility of shared variables among multiple threads is the guarantee of its safety. As shown in the following figure

1. Refresh the updated shared variable in working memory A to main memory
2, update the value of the latest shared variable in main memory to working memory B
, and do not allow other threads to update the latest shared variable during this period, but our code happens. During the judgment and execution of the first thread, the second thread modifies the shared variable (ordinary variable). When I rerun the above method using synchronized (synchronized mutex plus lock unlock), the following code

private static int num = 0;
    private static int volatileNum = 0;

    public static void main(String[] args) {
        new Thread(){
            public synchronized void run(){
                System.out.println("");
                while(num==0&&volatileNum ==0){
                    //System.err.println("--");
                }
                System.out.println("");
                System.exit(0);
            }
        }.start();

        new Thread(){
            public synchronized void run(){
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("");
                num = 1;
            }
        }.start();
    }

its running result is still an infinite loop, because synchronized ensures that the num and volatileNum in a single thread are acquired with the latest values of main memory, and updates are not pushed to the main storage when the run is not finished. Thread 2 updates have not yet obtained the latest value of num for the judging thread that gets the value for the first time, but I found an interesting problem of writing System.out.println (num); in while. After that, even under synchronized, the program ends the loop, but if there is no executing code in the while, it will continue to loop.
this gives me a strange idea: I modified the code

while (true){
        if(num==0&&volatileNum ==0){
            System.err.println("");
        }else if(num==1&&volatileNum ==0){
            System.out.println("");
            System.exit(0);
        }
    }
The result of

is that the loop ends when assigning, that is, after the assignment thread updates the num variable, it is pushed to main memory, and the judgment thread gets the latest num variable. At this time, the removal of synchronized does not have too much effect on it. The result is the same when volatileNum is re-added to volatile.

Multithreading is really interesting, and I find that I have to learn more about it. If you have any new ideas, you can let me know. I don't think my answer is correct.
you can take a look at my two recent articles, and I'd like to hear your opinion.
[Java cat said] Java multithreaded memory visibility
[Java cat said] Java multithreaded memory visibility (second part)


add some output information to the code as follows:

public class Main  {
    private static int a = 0;

    private volatile static int b = 0;

    public static void main(String[] args) {
        Test test = new Test();
        new Thread(){
            public void run(){
                System.out.println("");
                System.out.println("a:"+a);
                while(a==0&&b==0){
                    System.out.println("a:"+a);
                    //System.out.println("12312321312312321");
                }
                System.out.println("a:"+a);
                System.out.println("");
                System.exit(0);
            }
        }.start();

        new Thread(){
            public void run(){
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("");
                a=1;
            }
        }.start();
    }
}

run code output


a:0
a:0
a:0
 .
 .
 .
a:0
a:0

a:1

and then exchange the position of a while b as follows: while (b==0&&a==0) {
surprised to find that the output is somewhat different:


a:0
a:0
a:0
 .
 .
 .
a:0
a:0

a:0
a:1

searched the Internet and found this passage:

When thread A writes to a volatile variable and subsequently thread B reads the same variable, the values of all variables that were visible to A prior to writing to the volatile variable, become visible to B after reading the volatile variable.

has a general understanding that: thread A writes to the volatile variable, and then thread B reads the value of this variable. Before An is written, all values are visible to A (that is, A directly accesses memory, not the memory area of its own thread), and is visible to B after B is read in. So if you look at this situation, it should be because you read b first, so the next a will be visible to the update variable. If you read a first, this cycle will not succeed, but after reading b, the next cycle will succeed, which is why the result of two times will be one more cycle.

finally, reiterate the principle of using volitale:

  1. writes to variables do not depend on the current value.
  2. this variable is not included in an invariant with other variables.
Menu