您遇到的问题是您没有等待足够长的时间来优化代码和缓存值。
当 x86_64 系统上的线程第一次读取一个值时,它会获得一个线程安全副本。它只是后来的变化,它可能看不到。在其他 CPU 上可能不是这种情况。
如果你尝试这个,你会看到每个线程都被它的本地值卡住了。
public class RequiresVolatileMain {
static volatile boolean value;
public static void main(String... args) {
new Thread(new MyRunnable(true), "Sets true").start();
new Thread(new MyRunnable(false), "Sets false").start();
}
private static class MyRunnable implements Runnable {
private final boolean target;
private MyRunnable(boolean target) {
this.target = target;
}
@Override
public void run() {
int count = 0;
boolean logged = false;
while (true) {
if (value != target) {
value = target;
count = 0;
if (!logged)
System.out.println(Thread.currentThread().getName() + ": reset value=" + value);
} else if (++count % 1000000000 == 0) {
System.out.println(Thread.currentThread().getName() + ": value=" + value + " target=" + target);
logged = true;
}
}
}
}
}
打印以下内容,显示其翻转值,但卡住了。
Sets true: reset value=true
Sets false: reset value=false
...
Sets true: reset value=true
Sets false: reset value=false
Sets true: value=false target=true
Sets false: value=true target=false
....
Sets true: value=false target=true
Sets false: value=true target=false
如果我添加-XX:+PrintCompilation
这个开关发生在你看到的时间
1705 1 % RequiresVolatileMain$MyRunnable::run @ -2 (129 bytes) made not entrant
1705 2 % RequiresVolatileMain$MyRunnable::run @ 4 (129 bytes)
这表明代码已编译为本机是一种非线程安全的方式。
如果你创造了价值volatile
,你会看到它无休止地翻转价值(或者直到我感到无聊)
编辑:这个测试的作用是;当它检测到该值不是线程目标值时,它设置该值。IE。线程 0 设置为true
,线程 1 设置为false
当两个线程正确共享字段时,它们会看到彼此发生变化,并且值不断在真假之间翻转。
如果没有 volatile,这将失败,并且每个线程只能看到自己的值,因此它们都更改值和线程 0 看到true
和线程 1 看到false
相同的字段。