非易失性字段什么时候写入主存
When is non-volatile field write to main memory
因为 done
是非易失性的,所以我预计线程 1 将继续执行并打印出 "Done"。
但是当我运行这个程序时,这里是控制台的输出
Done
Undo
这意味着线程2的更新被线程1看到了,对吧? (但 done
不是易变字段。).
我的解释是线程 1 和线程 2 运行在同一个内核中。以便他们可以看到提交的更新,如果我错了,请纠正我。
总的来说,我的问题是为什么线程1可以看到线程2的变化?这与 CPU 缓存写入 back/through 到主内存有关吗?如果是,什么时候发生?
public class Done {
boolean done = true;
public void m1() throws InterruptedException {
while (this.done) {
System.out.println("Done");
}
System.out.println("Undo");
}
public void undo() {
done = false;
}
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
Done v = new Done();
es.submit(() -> {
try {
v.m1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}); // thread 1
es.submit(() -> {
v.undo();
}); // thread 2
es.shutdown();
}
}
Java memory model 的保证仅以一种方式起作用。如果某些东西是有保证的,比如易失性写入的可见性,那么它将在 100% 的时间内工作。
如果没有保证,并不意味着它永远不会发生。有时其他线程会看到非易失性写入。如果您 运行 在具有不同 JVM 的不同机器上多次执行此代码,您可能会看到不同的结果。
因为 done
是非易失性的,所以我预计线程 1 将继续执行并打印出 "Done"。
但是当我运行这个程序时,这里是控制台的输出
Done
Undo
这意味着线程2的更新被线程1看到了,对吧? (但 done
不是易变字段。).
我的解释是线程 1 和线程 2 运行在同一个内核中。以便他们可以看到提交的更新,如果我错了,请纠正我。
总的来说,我的问题是为什么线程1可以看到线程2的变化?这与 CPU 缓存写入 back/through 到主内存有关吗?如果是,什么时候发生?
public class Done {
boolean done = true;
public void m1() throws InterruptedException {
while (this.done) {
System.out.println("Done");
}
System.out.println("Undo");
}
public void undo() {
done = false;
}
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
Done v = new Done();
es.submit(() -> {
try {
v.m1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}); // thread 1
es.submit(() -> {
v.undo();
}); // thread 2
es.shutdown();
}
}
Java memory model 的保证仅以一种方式起作用。如果某些东西是有保证的,比如易失性写入的可见性,那么它将在 100% 的时间内工作。
如果没有保证,并不意味着它永远不会发生。有时其他线程会看到非易失性写入。如果您 运行 在具有不同 JVM 的不同机器上多次执行此代码,您可能会看到不同的结果。