假设有2个线程在共享队列q
上执行操作。每个线程的代码行都有编号,最初队列为空。
主题A:
A1) q.enq(x)
A2) q.deq()
主题B:
B1) q.enq(y)
假设执行顺序如下:
A1) q.enq(x)
B1) q.enq(y)
A2) q.deq()
因此我们得到y
(即q.deq()
返回y
)
这个执行是基于一本着名的书,据说是顺序一致的。请注意,方法调用不重叠。这怎么可能呢?我相信线程A执行A1而没有实际更新队列,直到它继续到A2行,但这只是我的猜测。如果我从The Java Language Specification中看到这个解释,我会更加困惑:
顺序一致性是对程序执行中的可见性和排序的有力保证。在顺序一致的执行中,所有单个操作(例如读取和写入)的总顺序与程序的顺序一致,并且每个单独的操作都是原子的,并且立即对每个线程可见。< /强>
如果是这种情况,我们就会出列x
。
我确定我错了。有人可以对此有所了解吗?
答案 0 :(得分:2)
请注意,顺序一致性的定义表示“与程序顺序一致”,而不是“与程序执行顺序一致”。
接着说:
如果某个程序没有数据竞赛,那么程序的所有执行都将显示,以便顺序保持一致。
(我强调“出现”)。
Java的内存模型不强制执行顺序一致性。正如JLS所说:
如果我们使用顺序一致性作为我们的内存模型,我们讨论过的许多编译器和处理器优化都是非法的。例如,在表17.3的跟踪中,只要发生3到p.x的写入,就需要后续读取该位置才能看到该值。
因此,Java的内存模型实际上并不支持顺序一致性。只是顺序一致性的出现。而这只需要某些顺序一致的动作顺序与程序顺序一致。
显然,线程A和B的某些执行可能导致A2返回y
,具体来说:
B1)q.enq(y)
A1)q.enq(x)
A2)q.deq()
因此,即使程序碰巧按照您指定的顺序执行,也有一个顺序可以执行“与程序顺序一致”,A2返回y
。因此,在这种情况下返回y
的程序仍然会呈现顺序一致的外观。
请注意,这不应被解释为说A2返回x
是非法的,因为有一个顺序一致的操作序列与程序顺序一致,可以给出结果。< / p>
另请注意,顺序一致性的这种外观仅适用于正确同步的程序。如果你的程序没有正确同步(即有数据竞赛),那么所有的赌注都会关闭。