星期四, 一月 20, 2022

Java volatile 关键字

没有评论

 本文使用汇编对 volatile 关键字进行分析

汇编参数
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintAssembly
-XX:+TraceClassLoading
-Xcomp
-XX:CompileCommand=dontinline,*VolatileTest.main
-XX:CompileCommand=compileonly,*VolatileTest.main
未使用 volatile 变量的示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.pohvii.note.basic.concurrent;

/**
 * @author zhanglei
 * @date 2021/5/31
 */
public class NoVolatileTest {
    static int a = 0;

    public static void main(String[] args) {
        if (a == 0) {
            a++;
        }
    }
}
未使用 volatile 变量的示例汇编码
  0x000000010af3a220: sub    $0x18,%rsp
  0x000000010af3a227: mov    %rbp,0x10(%rsp)    ;*synchronization entry
                                                ; - com.pohvii.note.basic.concurrent.NoVolatileTest::main@-1 (line 11)

  0x000000010af3a22c: movabs $0x66ab68b18,%r10  ;   {oop(a 'java/lang/Class' = 'com/pohvii/note/basic/concurrent/NoVolatileTest')}
  0x000000010af3a236: mov    0x68(%r10),%r8d    ;*getstatic a
                                                ; - com.pohvii.note.basic.concurrent.NoVolatileTest::main@0 (line 11)

  0x000000010af3a23a: test   %r8d,%r8d
  0x000000010af3a23d: je     0x000000010af3a24b  ;*return
                                                ; - com.pohvii.note.basic.concurrent.NoVolatileTest::main@14 (line 14)

  0x000000010af3a23f: add    $0x10,%rsp
  0x000000010af3a243: pop    %rbp
  0x000000010af3a244: test   %eax,-0x5c9a24a(%rip)        # 0x00000001052a0000
                                                ;   {poll_return}
  0x000000010af3a24a: retq   
  0x000000010af3a24b: inc    %r8d
  0x000000010af3a24e: mov    %r8d,0x68(%r10)    ;*putstatic a
                                                ; - com.pohvii.note.basic.concurrent.NoVolatileTest::main@11 (line 12)
使用 volatile 变量的示例代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.pohvii.note.basic.concurrent;

/**
 * @author zhanglei
 * @date 2021/5/31
 */
public class VolatileTest {
    static volatile int a = 0;

    public static void main(String[] args) {
        if (a == 0) {
            a++;
        }
    }
}
使用 volatile 变量的示例汇编码
  0x0000000109ca1360: sub    $0x18,%rsp
  0x0000000109ca1367: mov    %rbp,0x10(%rsp)    ;*synchronization entry
                                                ; - com.pohvii.note.basic.concurrent.VolatileTest::main@-1 (line 11)

  0x0000000109ca136c: movabs $0x66ab68ac0,%r10  ;   {oop(a 'java/lang/Class' = 'com/pohvii/note/basic/concurrent/VolatileTest')}
  0x0000000109ca1376: mov    0x68(%r10),%r8d    ;*getstatic a
                                                ; - com.pohvii.note.basic.concurrent.VolatileTest::main@0 (line 11)

  0x0000000109ca137a: test   %r8d,%r8d
  0x0000000109ca137d: je     0x0000000109ca138b  ;*return
                                                ; - com.pohvii.note.basic.concurrent.VolatileTest::main@14 (line 14)

  0x0000000109ca137f: add    $0x10,%rsp
  0x0000000109ca1383: pop    %rbp
  0x0000000109ca1384: test   %eax,-0x5d1038a(%rip)        # 0x0000000103f91000
                                                ;   {poll_return}
  0x0000000109ca138a: retq   
  0x0000000109ca138b: mov    0x68(%r10),%r8d
  0x0000000109ca138f: inc    %r8d
  0x0000000109ca1392: mov    %r8d,0x68(%r10)
  0x0000000109ca1396: lock addl $0x0,(%rsp)     ;*putstatic a
                                                ; - com.pohvii.note.basic.concurrent.VolatileTest::main@11 (line 12)

源代码部分:两者仅第8行不同,一个使用了 volatile 变量,另一个未使用

汇编码部分:使用 volatile 变量的汇编码在 a++ 之前多了一次读的操作,之后多了一条 lock 前缀的命令

stack

stack starts at a high memory address and grows downwards

$

Immediate values are constants, and are prefixed by a $

%

Register names are prefixed by a %

rsp

stack pointer, points to the top of the current stack frame

rbp

base pointer, points to the base of the current stack frame

LOCK (prefix)

The LOCK prefix ensures that the CPU has exclusive ownership of the appropriate cache line for the duration of the operation, and provides certain additional ordering guarantees. This may be achieved by asserting a bus lock, but the CPU will avoid this where possible. If the bus is locked then it is only for the duration of the locked instruction.

The cache coherency mechanism automatically prevents two or more processors that have cached the same area of memory from simultaneously modifying data in that area.

没有评论 :

发表评论