当前位置:网站首页>How can volatile memory be visible? Must it be invisible without volatile? "

How can volatile memory be visible? Must it be invisible without volatile? "

2020-11-06 01:17:33 Bugstack wormhole stack

author : Little brother Fu
Blog :https://bugstack.cn

precipitation 、 Share 、 grow up , Let yourself and others have something to gain !

One 、 Experience of yard

Are you a tough person ?

In the past, people who could bear hardships mostly referred to the hardships of physical labor , But now, being able to bear hardships already includes too many dimensions , Include : Read and study & The pain of loneliness Think deeply & Mental pain Self discipline habit & The pain of practice Self control & The pain of giving up Bow your head and be a man & The bitterness of dignity .

Although these are in front of us , But most people still like to eat simple bitter . Stay up late 、 Day after day 、 Repeat yesterday 、CRUD, Finally, the body becomes fat 、 Physical decline 、 Lack of ability 、 Hold yourself and cry ! So some bitterness can not eat without eating , If you want to eat, you should eat the bitterness with growth value .

Did you blog today ?

If a little thing can persist 5 In the above , Then you must be a great man . Yes , It's amazing . The most difficult thing for a person is to think clearly but can't do it , Or occasionally, you can't do it for a long time .

In fact, most of the partners on the road to R & D , They all know that they should work hard , But clearly made a good decision is not to hold on for long . It's like if you've ever thought about blogging about technology , Do technology accumulation . It's not until one day that you're stuck in a dilemma by a bottleneck , But it's really hard to break at this time !

Two 、 Interview questions

Thank you plane , Notes , Airplanes take advantage of the weekend , Eat hot pot . I went to have tea with the interviewer again !

Thank you plane : hi , I'm here , here , here .

interviewer : Why are you here again , I've learned a lot recently ?

Thank you plane : Still want to come to the big factory , Don't be shy , Meet me !

interviewer : I seem to be your make-up teacher … Now that it's here , Just ask you !volatile What are the ?

Thank you plane : ah ,volatile It ensures the visibility of variables to all threads .

interviewer : that volatile Can we solve the problem of atomicity ?

Thank you plane : Can not be !

interviewer : that volatile How to realize the underlying principle of ?

Thank you plane :…, this ! interviewer , I just asked two questions and then I dropped thunder , You don't have to be busy at home ?

interviewer : None of your business !

3、 ... and 、volatile Explain

1. Visibility case

public class ApiTest {

    public static void main(String[] args) {
        final VT vt = new VT();

        Thread Thread01 = new Thread(vt);
        Thread Thread02 = new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ignore) {
                }
                vt.sign = true;
                System.out.println("vt.sign = true  notice  while (!sign)  end !");
            }
        });

        Thread01.start();
        Thread02.start();
    }

}

class VT implements Runnable {

    public boolean sign = false;

    public void run() {
        while (!sign) {
        }
        System.out.println(" You are bad ");
    }
}

This code , Two threads operate on a variable , The program expects to be sign In a thread Thread01 Operated by vt.sign = true when ,Thread02 Output You are bad .

But in fact, this code will never output You are bad , It's been in a dead circle . Why is that ? Next, we will explain and verify step by step .

2. add volatile keyword

We put sign Keywords plus volatitle describe , as follows :

class VT implements Runnable {

    public volatile boolean sign = false;

    public void run() {
        while (!sign) {
        }
        System.out.println(" You are bad ");
    }
}

test result

vt.sign = true  notice  while (!sign)  end 
 You are bad 

Process finished with exit code 0

volatile Keywords are Java The lightest synchronization mechanism provided by virtual machines , It appears as a modifier , Used to modify variables , But it doesn't include local variables

Adding volatile The key word , The program will produce the expected output You are bad . From us to volatile We can know that .volatile Keywords are JVM The lightest synchronization mechanism available , Used to modify variables , Used to ensure the visibility of variables to all threads .

After modifying, you can make the field visible in the program , Then, after the attribute has been modified, the value , Can make corresponding response in another thread in time .

3. volatile How to ensure the visibility of

3.1 nothing volatile when , Memory changes

 nothing volatile when , Memory changes

The first is when sign No, volatitle When decorating public boolean sign = false;, Threads 01 Operate on variables , Threads 02 You don't get the value of the change . So the program will not output the result “ You are bad ”

3.2 Yes volatile when , Memory changes

 Yes volatile when , Memory changes

When we use variables volatile When decorating public volatile boolean sign = false;, Threads 01 When you operate on a variable , Will change the value of the variable forced refresh to main memory . When a thread 02 Get the value when , Will put their own memory sign Value expired , Then read it from main memory . So add keywords after the program as expected output results .

4. Decompilation and detoxification visibility

There's deep technical knowledge like this , The best way to do that is to understand the principles , See what it does to ensure memory visibility operations .

4.1 see JVM Instructions

Instructions javap -v -p VT

 public volatile boolean sign;
    descriptor: Z
    flags: ACC_PUBLIC, ACC_VOLATILE

  org.itstack.interview.test.VT();
    descriptor: ()V
    flags:
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_0
         6: putfield      #2                  // Field sign:Z
         9: return
      LineNumberTable:
        line 35: 0
        line 37: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lorg/itstack/interview/test/VT;

  public void run();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field sign:Z
         4: ifne          10
         7: goto          0
        10: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        13: ldc           #4                  // String  You are bad 
        15: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        18: return
      LineNumberTable:
        line 40: 0
        line 42: 10
        line 43: 18
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      19     0  this   Lorg/itstack/interview/test/VT;
      StackMapTable: number_of_entries = 2
        frame_type = 0 /* same */
        frame_type = 9 /* same */
}

from JVM There's only a lot more to be found in the script ,ACC_VOLATILE, There are no other points . therefore , You can't see how visibility is achieved .

4.2 Look at the assembly instructions

adopt Class File view assembly , Need to download hsdis-amd64.dll file , Copied to the JAVA_HOME\jre\bin\server Under the table of contents . Download resources as follows :

The other is to execute orders , Include :

  1. Basic instructions :java -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
  2. Specify print :-XX:CompileCommand=dontinline, Class name . Method name
  3. Specify print :-XX:CompileCommand=compileonly, Class name . Method name
  4. Output location :> xxx

End use :java -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=dontinline,ApiTest.main -XX:CompileCommand=compileonly,ApiTest.mian

Instructions can be in IDEA Medium Terminal Use in , You can also go to DOS Use in black window

in addition , For easier use , We can configure instructions to idea Of VM options in , Here's the picture :

Idea VM options  Configure compilation instructions

When the configuration is complete , The results are as follows :

Loaded disassembler from C:\Program Files\Java\jdk1.8.0_161\jre\bin\server\hsdis-amd64.dll
Decoding compiled method 0x0000000003744990:
Code:
Argument 0 is unknown.RIP: 0x3744ae0 Code size: 0x00000110
[Disassembling for mach='amd64']
[Entry Point]
[Constants]
  # {method} {0x000000001c853d18} 'getSnapshotTransformerList' '()[Lsun/instrument/TransformerManager$TransformerInfo;' in 'sun/instrument/TransformerManager'
  #           [sp+0x40]  (sp of caller)
  0x0000000003744ae0: mov     r10d,dword ptr [rdx+8h]
  0x0000000003744ae4: shl     r10,3h
  0x0000000003744ae8: cmp     r10,rax
  0x0000000003744aeb: jne     3685f60h          ;   {runtime_call}
  0x0000000003744af1: nop     word ptr [rax+rax+0h]
  0x0000000003744afc: nop
[Verified Entry Point]
  0x0000000003744b00: mov     dword ptr [rsp+0ffffffffffffa000h],eax
  0x0000000003744b07: push    rbp
  0x0000000003744b08: sub     rsp,30h           ;*aload_0
                                                ; - sun.instrument.TransformerManager::getSnapshotTransformerList@0 (line 166)

  0x0000000003744b0c: mov     eax,dword ptr [rdx+10h]
  0x0000000003744b0f: shl     rax,3h            ;*getfield mTransformerList
                                                ; - sun.instrument.TransformerManager::getSnapshotTransformerList@1 (line 166)

  0x0000000003744b13: add     rsp,30h
...

The result of running is assembly instruction , There are a lot of them . We're only looking at the key parts :

   0x0000000003324cda: mov    0x74(%r8),%edx     ;*getstatic state
                                                 ; - VT::run@28 (line 27)
 
   0x0000000003324cde: inc    %edx
   0x0000000003324ce0: mov    %edx,0x74(%r8)
   0x0000000003324ce4: lock addl $0x0,(%rsp)     ;*putstatic state
                                                 ; - VT::run@33 (line 27)

In the compiled assembly instructions , Yes volatile Keywords and no volatile keyword , The main difference is that there is one more lock addl $0x0,(%rsp), That is to say lock The prefix instruction of .

lock Instructions Equivalent to one Memory barrier , It guarantees the following three points :

  1. Write the processor's cache to memory .
  2. When reordering, you cannot reorder subsequent instructions to the position in front of the memory barrier .
  3. If it is a write action, it will cause the corresponding memory in other processors to be invalid .

that , there 1、3 It's used to guarantee the modified variables , Ensure memory visibility .

5. No addition volatile Is it visible

If there is doubt, there must be verification

Let's revise the example again , stay while (!sign) Add an execution code to the loop body , as follows ;

class VT implements Runnable {

    public boolean sign = false;

    public void run() {
        while (!sign) {
            System.out.println(" Hello ");
        }
        System.out.println(" You are bad ");
    }
    
}

After the amendment, it was removed volatile keyword , And in while Add a piece of code to the loop . Now the running result is :

...
 Hello 
 Hello 
 Hello 
vt.sign = true  notice  while (!sign)  end 
 You are bad 

Process finished with exit code 0

how , You can see it again !

This is because there is no volatile When decorating ,jvm We will also try to ensure visibility .​ Yes volatile When decorating , Make sure you have visibility .

Four 、 summary

  • Finally, let's sum up volatile, It? , It will control the modified variables to actively refresh the value to main memory in memory operation ,JMM This thread will correspond to CPU Memory settings expired , Read the latest value from main memory .
  • that ,volatile How to prevent instruction rearrangement is also a memory barrier ,volatile The memory screen failure is to add one before and after the read and write operation StoreStore barrier , That's four places , To ensure that the instructions behind the memory barrier cannot be reordered to the position before the memory barrier when reordering .
  • in addition volatile It doesn't solve the problem of atomicity , If you need to solve the problem of atomicity , Need to use synchronzied perhaps lock, This part will be introduced in the following chapters .

5、 ... and 、 Series recommendation

( Please indicate the author and source of this article WeChat official account :bugstack Wormhole stack | author : Little brother Fu

Show Disqus Comments

版权声明
本文为[Bugstack wormhole stack]所创,转载请带上原文链接,感谢