Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How can volatile be implemented in memory?

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "how to achieve volatile memory visible", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "how to make volatile visible in memory".

Volatile explanation 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 notifies while (! sign) to end!")

}

});

Thread01.start ()

Thread02.start ()

}

}

Class VT implements Runnable {

Public boolean sign = false

Public void run () {

While (! sign) {

}

System.out.println ("you bad")

}

}

"this code" is two threads operating on a variable, and the program expects sign to output you bad when thread Thread01 is manipulated vt.sign = true.

But in fact, this code will never output you bad, but always in an endless loop. Why is that? Next, we will explain and verify it step by step.

two。 Add the volatile keyword

Let's add the volatitle description to the sign keyword, as follows:

Class VT implements Runnable {

Public volatile boolean sign = false

Public void run () {

While (! sign) {

}

System.out.println ("you bad")

}

}

"Test results"

Vt.sign = true notifies while (! sign) to end!

You're bad.

Process finished with exit code 0

The volatile keyword is the lightest synchronization mechanism provided by the Java virtual machine. It appears as a modifier to modify variables, but local variables are not included here.

After adding the volatile keyword, the program will output your bad as expected. We can know from our knowledge of volatile. The volatile keyword is the lightest synchronization mechanism provided by JVM, which is used to modify variables and to ensure that variables are visible to all threads.

After being modified, you can make the field visible to the thread, so after the value of this property is modified, you can respond in time in another thread.

3. How to ensure the visibility of volatile 3.1 when there is no volatile, the memory changes when there is no volatile.

The first is that when sign has no volatitle modification, thread 01 public boolean sign = false;, operates on the variable, and thread 02 does not get the changed value. So the program won't output the result "you're bad."

3.2 when there is volatile, the memory changes when there is volatile.

When we modify the variable with volatile, public volatile boolean sign = false;, thread 01 operates on the variable, forcing the value of the variable change to be refreshed to the main memory. When thread 02 gets the value, it expires the sign value in its own memory and then reads it from the main memory. So after adding keywords, the program outputs the results as expected.

4. Decompiler detoxification visibility

The best way to have in-depth technical knowledge like this is to have a deep understanding of the principle and see what it does to ensure memory visibility.

4.1 View JVM directives

"instruction": 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. "() 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 * /

}

You can only find too much in the JVM script, ACC_VOLATILE, and nothing else. So, you can't see how the visibility is achieved.

4.2 View assembly instructions

To view the assembly through the Class file, you need to download the hsdis-amd64.dll file and copy it to the JAVA_HOME\ jre\ bin\ server directory. The download resources are as follows:

Http://vorboss.dl.sourceforge.net/project/fcml/fcml-1.1.1/hsdis-1.1.1-win32-amd64.ziphttp://vorboss.dl.sourceforge.net/project/fcml/fcml-1.1.1/hsdis-1.1.1-win32-i386.zip

The other is to execute orders, including:

Basic instruction: java-Xcomp-XX:+UnlockDiagnosticVMOptions-XX:+PrintAssembly specifies print:-XX:CompileCommand=dontinline, class name. The method name specifies the print:-XX:CompileCommand=compileonly, class name. Output location of method name: > xxx

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

Instructions can be used in Terminal in IDEA or in the DOS black window

In addition, for easier use, we can configure the instruction into the VM options of idea, as shown in the following figure:

Idea VM options configuration compilation instruction

After the configuration is completed, the non-unexpected running 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 the run is the assembly instruction." if there are more, they won't all be put here. We only observe. 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, there is a volatile keyword and no volatile keyword, the main difference is that there is a lock addl $0x0, (% rsp), that is, the prefix instruction of lock.

The "lock instruction" acts as a memory barrier and guarantees the following three points:

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

So, the 1 and 3 here are used to ensure the modified variables and memory visibility.

5. Can you see it without volatile?

Where there is doubt, there must be verification.

Let's now modify the example to add a piece of execution code to the body of the while (! sign) loop, as follows

Class VT implements Runnable {

Public boolean sign = false

Public void run () {

While (! sign) {

System.out.println ("Hello")

}

System.out.println ("you bad")

}

}

After modification, the volatile keyword is removed and a piece of code is added to the while loop. The result of the current operation is:

...

Hello

Hello

Hello

Vt.sign = true notifies while (! sign) to end!

You're bad.

Process finished with exit code 0 so far, I believe you have a deeper understanding of "how volatile is visible in memory". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report