【问题标题】:Sequential consistency volatile explanation顺序一致性 volatile 解释
【发布时间】:2018-04-04 00:23:39
【问题描述】:

我正在观看来自 java jpoint 会议的视频。

我对@9​​87654321@ 报告中的以下幻灯片有疑问:

对不起,幻灯片上的非英语。实际上作者说变量集是不可能的

r1 = 1 (Y)
r2 = 0 (x)
r3 = 1 (x)
r4 = 0 (Y)

根据视频,他暗示很明显。

有人能解释一下为什么这个值根据 JMM 设置是不可能的吗?

附言

如果我理解 Alexey 符号是正确的,它尊重以下代码:

public class SequentialConsistency {
    static volatile int x;
    static volatile int y;

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                x = 1;
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                y = 1;
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("r1=" + x + ", r2=" + y);
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("r3=" + x + ", r4=" + y);
            }
        }).start();
    }
}

【问题讨论】:

  • 当您的代码没有 volatile x,y; 并且没有 r3 和 r4 时,为什么您的代码会正确表示幻灯片?
  • @Erwin Bolwidt 我无法翻译你的问题。你能改写一下吗?
  • 您的代码中的 x、y、r3 和 r4 在哪里?
  • 哎呀,对不起。一瞬间
  • @Erwin,我更正了。我没有明确地创建 r1-r4 但我相信它显然是

标签: java multithreading concurrency volatile java-memory-model


【解决方案1】:

您可以为此代码构建详尽的 SC 执行列表,并实现没有 SC 执行收益率 (1, 0, 1, 0)。

在模型方面,很容易争论。同步顺序 (SO) 一致性表示同步读取应该看到 SO 中的最后一个同步写入。 SO-PO 一致性表示 SO 应该与程序顺序一致。

这允许通过矛盾勾勒出证明。假设产生 (1, 0, 1, 0) 的执行存在。然后,由于 SO 一致性,在那些读取中看到零必须按此顺序排列:

(r2 = x):0 --so--> (x = 1)  [1]
(r4 = y):0 --so--> (y = 1)  [2]

...另外两个读取必须按此顺序写入才能看到它们(由于 SO 一致性):

(x = 1) --so--> (r3 = x):1  [3]
(y = 1) --so--> (r1 = y):1  [4]

...此外,由于 SO-PO 的一致性:

(r1 = y):1 --po--> (r2 = x):0  [5]
(r3 = x):1 --po--> (r4 = y):0  [6]

这会产生奇怪的循环 SO:

(r2 = x):0 --so--> (r3 = x):1 --so--> (r4 = y):0 --so--> (r1 = y):1 --so--> (r2 = x):0
            [1,3]               [6]               [2,4]               [5]

请注意,对于上述执行中的任何一对动作 A != B,我们可以说 (A --so--> B)(B --so--> A) - 这称为对称性。根据定义,SO 是全序,全序是反对称,这里我们有对称的。我们已经到了矛盾的地步,因此这种处决是不存在的。 Q.E.D.

【讨论】:

    【解决方案2】:

    相信我明白了。

    假设我们有 4 个线程。 t1-t4(如图从左到右)

    t3 读取 y 然后 x 我们看到结果

    y=1
    x=0
    

    表示顺序如下:

    1. t1y
    2. t3 读作 y
    3. t3 读取 x
    4. t2x

    这是唯一可能的序列。

    让我们检查一下 t4 读数:

    x=1
    y=0
    

    根据t3的推理,这意味着

    t2 write 发生在 t1 write 之前,但它与 t3 输出相矛盾,因此不可能

    【讨论】:

    • 因为变量被标记为易失性,它们没有存储在线程本地内存中,它们保留在 jvm 主内存中。这意味着 y = 1 对于所有线程都是正确的,因此如果值已设置为 1,则任何线程都无法读取 y = 0。如果未标记为 volatile 的值,则线程可能有任何给定的值序列,因为该值将存储在线程内存中。这意味着每个线程可以包含相同变量的不同值。这在我身上发生了很多次,本地线程内存很痛苦。
    • @MissingSemiColon 没有“JVM主内存”之类的东西,因此,您解释中的所有内容都没有意义
    • 好吧,很公平。但这不是关于java如何详细管理内存。您可以在以下所有文章中找到“主存储器”一词:tutorials.jenkov.com/java-concurrency/volatile.htmlbaeldung.com/java-volatilejavamex.com/tutorials/synchronization_volatile.shtml。仅供参考。
    【解决方案3】:

    你可以用一种更简单的形式来考虑它(尽管你不能比阿列克谢说的更正确)。 java 中的volatile 提供sequential consistency,这意味着操作以全局和原子顺序类似 完成。如果你写到一个字段(x = 1),每个人都会看到那个写的。为了根据您的示例使其更正确,如果有一个ThreadA 执行x = 1,则ThreadB(即r2 = x)和ThreadC(即r3 = x)都将读取@987654330 @是1。这就是顺序一致性的保证。

    幻灯片显示在SC(顺序一致)执行中:1, 0, 1, 0 是不可能的。因为那意味着:

    ThreadA wrote to x value of 1
    ThreadB observed that value to be 1 (via r2 = x)
    ThreadC observed that value to be 0 (via r3 = x)
    

    但是在 SC 世界中,一旦发生写入(我们知道它发生是因为 ThreadB 已经观察到它),其他人都必须观察到它。这不是这里的情况:ThreadCx 视为0。因此,这会破坏 SC。

    您必须记住他的观点是 - “我们可以用 release/acquire 替换每个 volatile 吗?(毕竟它更便宜)”。答案是否定的,因为 SC 禁止 1, 0, 1, 0,而release/acquire 允许

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-09
      • 1970-01-01
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 2017-04-17
      • 1970-01-01
      • 2022-01-19
      相关资源
      最近更新 更多