Java允许输出1, 0吗?我已经对它进行了非常深入的测试,但我无法得到这个输出。我只得到1, 1,0, 0或0, 1。
public class Main {
private int x;
private volatile int g;
// Executed by thread #1
public void actor1(){
x = 1;
g = 1;
}
// Executed by thread #2
public void actor2(){
put_on_screen_without_sync(g);
put_on_screen_without_sync(x);
}
}为什么?
在我看来,获得1, 0是可能的。我的推理。g是不稳定的,因此它会导致内存顺序得到保证。所以,看起来:
actor1:
(1) store(x, 1)
(2) store(g, 1)
(3) memory_barrier // on x86并且,我看到了以下情况:在store(x,1)之前重新排序store(x,1) (memory_barrier是(2)之后的)。现在,运行线程#2。那么,g = 1, x = 0。现在,我们已经预计到了产出。我的推理有什么不正确的?
发布于 2017-07-16 22:43:18
在易失性写入之前的任何操作都发生在(HB)之前,也就是相同变量的任何后续易失性读取。在您的示例中,对x的写入发生在写入g之前(由于程序顺序)。
所以只有三种可能性:
x=1 (而不是g=1),输出可以是0,1或0,0 (没有易失性写入,因此不能保证)。发布于 2017-07-16 22:47:21
不,这不可能。根据JMM,当线程1写入易失性字段时,线程1可以看到的任何内容在读取该字段时对线程2都是可见的。
还有另一个类似于您的在此提供的例子
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}发布于 2020-11-30 17:13:28
您将永远不会看到1, 0,但是正确地解释这一点并不容易,规范是明智的。首先,让我们把一些显而易见的东西从门里拿出来。规范他说
如果x和y是同一个线程的动作,x以程序顺序在y之前,则hb(x,y)。
这意味着在写入线程端、hb(x, g)和读取端hb(g, x)。但是,只有在您必须对每个线程说:进行推理的情况下,情况才会如此。
在每个线程执行的所有inter-thread操作中.
因此,如果您设想一次运行每个线程,那么happens-before对每个线程都是正确的。但是你没有。你的演员(我相信你在那里使用jcstress )同时运行。因此,仅仅依靠“程序顺序”进行推理是不够的(两者都不正确)。
你需要在某种程度上同步这两个动作--读和写。这是规格说明是怎么做的?
对易失性变量synchronizes-with的写入(所有后续的线程都会读取v)(其中“后继”是根据同步顺序定义的)。
后来说:
如果一个动作x synchronizes-with是跟随动作y,那么我们也有hb(x,y)。
如果你现在把所有这些放在一起:
(hb) (hb) (hb)
write(x) ------> write(g) -------> read(g) -------> read(x)这也被称为“临时”关闭program order和synchronizes-with order。由于每一步都有hb,根据规范,不可能看到1, 0 (一个生动的阅读)。
https://stackoverflow.com/questions/45133832
复制相似问题