gpt4 book ai didi

Java 内存模型 : a JLS statement about sequential consistency seems incorrect

转载 作者:行者123 更新时间:2023-12-03 11:17:14 25 4
gpt4 key购买 nike

我在看 Chapter 17. Threads and Locks of JLS以下关于 Java 中顺序一致性的陈述对我来说似乎不正确:

If a program has no data races, then all executions of the program will appear to be sequentially consistent.


他们将数据竞争定义为:

When a program contains two conflicting accesses (§17.4.1) that are not ordered by a happens-before relationship, it is said to contain a data race.


他们将冲突访问定义为:

Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.


最后,他们有以下关于发生在关系之前的事情:

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.


我对第一个语句的问题是,我认为我可以提出一个没有数据竞争并允许顺序不一致执行的 Java 程序:
// Shared code
volatile int vv = 0;
int v1 = 0;
int v2 = 0;


// Thread1 Thread2
v1 = 1;
v2 = 2;
vv = 10; while(vv == 0) {;}
int r1 = v1;
int r2 = v2;
System.out.println("v1=" + r1 + " v2=" + r2);
v1 = 3;
v2 = 4;
vv = 20;
在上面的代码中,我还用缩进展示了线程的代码在运行时是如何交错的。
所以,据我所知,这个程序:
  • 没有数据竞争:线程 2 中 v1 和 v2 的读取与线程 1 中的写入同步
  • 可以输出v1=1 v2=4 (这违反了顺序一致性)。

  • 因此,来自 JLS 的初始声明

    If a program has no data races, then all executions of the program will appear to be sequentially consistent.


    对我来说似乎不正确。
    我是否遗漏了什么或我在某处犯了错误?
    编辑:用户 chrylis-cautiouslyoptimistic正确指出我给出的代码可以输出 v1=1 v2=4具有顺序一致性——线程代码中的行应该以稍微不同的方式交错。
    所以这里是稍微修改的代码(我改变了读取顺序),顺序一致性不能输出 v1=1 v2=4 ,但一切仍然适用。
    // Shared code
    volatile int vv = 0;
    int v1 = 0;
    int v2 = 0;


    // Thread1 Thread2
    v1 = 1;
    v2 = 2;
    vv = 10; while(vv == 0) {;}
    int r2 = v2;
    int r1 = v1;
    System.out.println("v1=" + r1 + " v2=" + r2);
    v1 = 3;
    v2 = 4;
    vv = 20;

    最佳答案

    您的错误在要点#1:v1 的读数和 v2不同步。
    只有与 vv 的交互才会创建发生之前的关系。 ,例如在这种情况下,如果您添加了 vv到打印语句的开头,您肯定不会看到 vv=20,v2=4 .由于您忙-等待vv变为非零,然后不再与它交互,唯一的保证是您将看到它变为非零之前发生的所有效果(1 和 2 的赋值)。您可能还会看到 future 的影响,因为您没有任何进一步的发生之前。
    即使您将所有变量声明为 volatile,您仍然可以输出 v1=1,v2=4因为变量的多线程访问没有定义的顺序,全局顺序可以是这样的:

  • T1:写 v1=1
  • T1:写 v2=2
  • T1:写 vv=10 (线程 2 不能在此之前退出 while 循环,并且保证看到所有这些效果。)
  • T2:阅读 vv=10
  • T2:阅读 v1=1
  • T1:写 v1=3
  • T1:写 v2=4
  • T2:阅读 v2=4

  • 在每个步骤之后,内存模型保证所有线程都会看到 volatile 变量的相同值,但是您有数据竞争,这是因为访问不是原子的(分组的)。为了确保你在一个组中看到它们,你需要使用一些其他的方式,比如在 synchronized 中执行。阻止或将所有值放入记录类并使用 volatileAtomicReference换出整个记录。
    正式地,JLS 定义的数据竞争包括操作 T1(写 v1=3)和 T2(读 v1)(以及 v2 上的第二个数据竞争)。这些是有冲突的访问(因为 T1 访问是写),但是虽然这两个事件都发生在 T2(读 vv)之后,但它们之间没有相互排序。

    关于Java 内存模型 : a JLS statement about sequential consistency seems incorrect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65527237/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com