java - Java内存模型中具有数据竞争的正确同步程序的示例

标签 java memory-model jls

JLS, §17.4.5. Happens-before Order中,它说

A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.



根据Does a correctly synchronized program still allow data race?(Part I)中的讨论,我们得出以下结论:

A program can be correctly synchronized and have data races.



两个结论的组合意味着它必须存在这样的示例:

All sequentially consistent executions of a program are data race free, but the normal executions (executions other than sequentially consistent executions) of such a program contain data race.



经过深思熟虑,我仍然找不到这样的代码示例。那你呢

最佳答案

“程序可以正确同步并具有数据竞争”是不正确的。在该讨论中,assylias的示例未正确同步。从更高级别的功能角度来看,它是正确的-它包含的数据竞争不会表现为错误。这是所谓的“良性”数据竞争,但是在讨论JLS定义时这是无关紧要的。
保证顺序一致执行不包含数据竞争的程序在任何执行中都不会包含数据竞争,无论顺序一致与否。正如JLS所说,

This is an extremely strong guarantee for programmers. Programmers do not need to reason about reorderings to determine that their code contains data races. Therefore they do not need to reason about reorderings when determining whether their code is correctly synchronized. Once the determination that the code is correctly synchronized is made, the programmer does not need to worry that reorderings will affect his or her code.


因此,请注意,出于对程序员的礼貌,正确同步的程序的定义已缩小到仅顺序一致的执行,这为他提供了强有力的保证,即顺序一致的执行是他或她唯一需要推理和执行所有其他执行的命令将自动具有相同的保证。
更新
JMM使用的术语很容易迷失,并且细微的误解会在以后引起深刻的误解。因此,请谨记以下几点:
  • 执行只是一组线程间操作。没有先验顺序。特别是,没有,没有时间顺序

  • 这是一个违反直觉的定义,因此我们必须谨慎对待:每次执行时,我们都必须确保想象一个 Action 包,从不包含任何字符串。每当我们定义偏序时,我们都应该想象几个袋子排列在中。
  • 程序包含执行操作的指令。每个这样的指令可以执行零次或更多次,从而为特定执行贡献零次或更多次独特的 Action ;
  • 执行可能有执行顺序,也可能没有,这是所有 Action 的总顺序;
  • 一个顺序一致的执行是如果所有共享变量都是volatile的,您将获得。这种执行总是有一个确定的执行顺序。
  • 顺序不一致执行是您在程序中的实际执行:涉及非 volatile 变量,并且编译器对读取和写入进行重新排序,有缓存,线程本地存储等。
  • 同步顺序是执行执行的所有同步操作的总顺序。关于执行本身,它仍然是部分顺序的,因为并非所有 Action 都是同步 Action 。最值得注意的是,读写非 volatile 变量。每次执行(无论顺序是否一致)都具有确定的同步顺序;
  • 同样,在为程序的特定执行定义顺序之前,发生,并且作为与程序顺序的同步顺序的传递闭包而派生。

  • 有趣的是,如果所有共享变量都是 volatile 的,则同步顺序将变为总顺序,因此将满足执行顺序的定义。这样,我们从不同的角度得出这样的结论,即该程序的所有执行将顺序一致。
    我已经深入研究了数据争用的定义中的JLS错误:
    “当程序包含两个冲突访问(第17.4.1节),而这些访问没有按事前发生关系进行排序时,就说它包含一个数据争用。”
    首先,不是程序包含数据竞争,而是程序执行。如果回头引用定义Java内存模型的original paper,我们将看到已更正的错误:
    “如果两次访问x和y来自不同的线程,它们会冲突,并且不会按先有先后的顺序排列,则它们会在程序执行中形成数据争用。”
    但是,这仍然使我们对定义为数据竞争的 volatile 变量采取的措施。请考虑以下发生在图表之前的情况:
    Thread W        w1 ----> w2
                    |
                     \
    Thread R     r0 ----> r1
    
    r1观察到写入w1。它之前是另一个读r0,而写之后是另一个读w2。现在注意r0和w1或w2之间没有路径;同样在r1和w2之间。根据定义,所有这些都是数据竞争的示例。
    深入研究,但是,我发现this post on the memoryModel mailing list。它说“一个数据
    种族应定义为对非 volatile 变量的冲突 Action
    “没有按事前发生的顺序进行排序”。只有添加了该漏洞后,漏洞才会被关闭,但这尚未进入JLS的正式发布。

    关于java - Java内存模型中具有数据竞争的正确同步程序的示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12024070/

    相关文章:

    java - 使用 JMAP 进行堆转储时出现异常

    java - 使用 JAXB 在 Jersey RESTful API 的 JSON 输出中包含空元素

    c# - 为什么标准 C# 事件调用模式是线程安全的,没有内存屏障或缓存失效?类似的代码呢?

    linux - 如何理解 "A formal kernel memory-ordering model"中的试金石 #5?

    java - Java 泛型类型中的通配符参数在其范围内的正式条件是什么?

    java - 如何将任何输入的 XML 文件转换为类似的 Java 对象结构?

    java - 使用 java thumbnailator 或 imgscalr 调整 jpeg 图像大小时出现粉红色/红色调

    java - 并发代码中赋值运算符的返回值

    java - Java 中是否保证从左到右的操作顺序?