我正在尝试深入Java中的volatile
关键字并设置2个测试环境。我相信他们俩都使用x86_64并使用热点。
Java version: 1.8.0_232
CPU: AMD Ryzen 7 8Core
Java version: 1.8.0_231
CPU: Intel I7
代码在这里:
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class Test {
private boolean flag = true; //left non-volatile intentionally
private volatile int dummyVolatile = 1;
public static void main(String[] args) throws Exception {
Test t = new Test();
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setaccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
Thread t1 = new Thread(() -> {
while (t.flag) {
//int b = t.someValue;
//unsafe.loadFence();
//unsafe.storeFence();
//unsafe.fullFence();
}
System.out.println("Finished!");
});
Thread t2 = new Thread(() -> {
t.flag = false;
unsafe.fullFence();
});
t1.start();
Thread.sleep(1000);
t2.start();
t1.join();
}
}
“完成!”永远不会打印出来,这对我来说毫无意义。我期望线程2中的fullFence
使flag = false
全局可见。
根据我的研究,Hotspot使用lock/mfence
在x86上实现fullFence
。根据{{3}}
此序列化操作可确保以程序顺序在MFENCE指令之前的每个加载和存储指令在MFENCE指令之后的任何加载或存储指令之前都是全局可见的。
即使是“更糟糕”,如果我在线程2中注释掉fullFence
并在线程1中取消注释xxxFence
中的任何一个,代码也会打印出“完成!”。因为至少有Intel's instruction-set reference manual entry for mfence,所以这没有什么意义。
我的信息来源可能不准确,或者我误会了一些东西。请帮忙,谢谢!