【发布时间】:2021-07-19 23:30:04
【问题描述】:
有关 AtomicInteger.lazySet() 的背景,请参阅AtomicInteger lazySet vs. set 的现有讨论。
所以根据 AtomicInteger.lazySet() 的语义,在 x86 CPU 上,AtomicInteger.lazySet() 相当于对 AotmicInteger 的值进行正常的写操作,因为 x86 内存模型保证了写操作之间的顺序。
但是,AtomicInteger.lazySet() 的运行时行为在 JDK 8 Hotspot JVM 中的 interperter 和 JIT 编译器(特别是 C2 编译器)之间是不同的,这让我很困惑。
首先,为演示创建一个简单的 Java 应用程序。
import java.util.concurrent.atomic.AtomicInteger;
public class App {
public static void main (String[] args) throws Exception {
AtomicInteger i = new AtomicInteger(0);
i.lazySet(1);
System.out.println(i.get());
}
}
然后,转储来自 C2 编译器提供的 instrinc 方法的 AtomicInteger.lazySet() 指令:
$ java -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:CompileCommand=print,*AtomicInteger.lazySet App
...
0x00007f1bd927214c: mov %edx,0xc(%rsi) ;*invokevirtual putOrderedInt
; - java.util.concurrent.atomic.AtomicInteger::lazySet@8 (line 110)
如您所见,操作正如预期的正常写入。
然后,使用 GDB 跟踪 AtomicInteger.lazySet() 解释器的运行时行为。
$ gdb --args java App
(gdb) b Unsafe_SetOrderedInt
0x7ffff69ae836 callq 0x7ffff69b6642 <OrderAccess::release_store_fence(int volatile*, int)>
0x7ffff69b6642:
push %rbp
mov %rsp,%rbp
mov %rdi,-0x8(%rbp)
mov %esi,-0xc(%rbp)
mov -0xc(%rbp),%eax
mov -0x8(%rbp),%rdx
xchg %eax,(%rdx) // the write operation
mov %eax,-0xc(%rbp)
nop
pop %rbp
retq
你可以看到,操作实际上是一个XCHG指令,它具有隐含锁语义,它带来了AtomicInteger.lazySet() 旨在消除的性能开销。
有谁知道为什么会有这样的差异?谢谢。
【问题讨论】:
标签: concurrency jvm atomic