Java内存模型是否保证线程内写入的可见性?

Java内存模型是否保证线程内写入的可见性?,java,Java,考虑一个简单的单线程Java程序执行,它不涉及同步操作,只涉及实例变量的简单读写。简单地忽略所有写入的实现似乎符合Java内存规范。首先,适用的一般声明来自: 内存模型确定在程序中的每个点可以读取哪些值。每个独立线程的操作必须由该线程的语义控制,但每个读取所看到的值由内存模型确定的情况除外 相关的约束条件如下(): 1.在程序顺序导致的排序之前发生: 如果x和y是同一线程的动作,并且x在程序顺序中位于y之前,那么hb(x,y) 2.发生在一致性之前: 如果对于A中的所有读取r,其中W(r)是r看

考虑一个简单的单线程Java程序执行,它不涉及同步操作,只涉及实例变量的简单读写。简单地忽略所有写入的实现似乎符合Java内存规范。首先,适用的一般声明来自:

内存模型确定在程序中的每个点可以读取哪些值。每个独立线程的操作必须由该线程的语义控制,但每个读取所看到的值由内存模型确定的情况除外

相关的约束条件如下():

1.在程序顺序导致的排序之前发生: 如果x和y是同一线程的动作,并且x在程序顺序中位于y之前,那么hb(x,y)

2.发生在一致性之前: 如果对于A中的所有读取r,其中W(r)是r看到的写操作,则A中的一组操作A在一致之前发生,而不是hb(r,W(r))或A中存在写操作W,使得W.v=r.v和hb(W(r),W)和hb(W,r)

这基本上排除了在观察到写入之前发生读取。另一项规定只是一个健全的条款,它防止对某个
v
的读取看到该
v
之前的写入,而该
v
之前的写入是在同一
v
之后的

我找不到任何保证,无论写什么都会被积极遵守,只有写什么的限制可能不会被遵守

我错过了什么?JVM真的有可能忽略这样一个微不足道的保证吗?

让我们使用:

class MyClass {
    private static int i = 0;

    public static void main(String[] args) {
        i = 3; //w
        System.out.println(i); //r
    }
}
  • 当且仅当所有顺序一致的执行都没有数据争用时,程序才正确同步
  • 如果一个程序正确同步,则该程序的所有执行看起来都是顺序一致的(§17.4.3)
  • 当一个程序包含两个冲突的访问(§17.4.1),而这两个访问不是由“先发生后发生”关系排序时,则称其包含数据竞争

    您的程序是单线程的
    =>我们有来自程序顺序约束的hb(w,r)
    =>它已正确同步
    =>程序的所有执行顺序都将保持一致。
    =>它将打印3


我不确定您觉得缺少什么保证。你能举个例子说明这会在哪里引起问题吗?如果A)未读取b)在读取前过度写入,则不会观察到写入。重要的是你读什么。一个简单的
this.i=3;System.out.println(this.i)不保证打印3。它可以打印0(初始值,我想这是唯一一个保证存在的值)。我可以感觉到头痛的到来,随之而来的是困惑,然后是惊讶:我需要一杯可乐……内存模型假设单线程将按照您的预期运行<代码>每个独立线程的行为必须由该线程的语义控制,
它唯一的多个线程内存模型有什么有趣的东西要说。@assylias你知道可口可乐的名字是因为它里面有可卡因吗。当可卡因变得非法时,它被咖啡因所取代@MarkoTopolnik您今天很容易放弃;-)是的,与上次相比有很大的变化。。。我能说什么呢,这听起来不错,感觉不错,在盯着它看了几分钟之后(包括过去两周里盯着JLS看的所有内容),我认为这个论点是无可挑剔的。我错过了与“看起来顺序一致”的联系,这本身就带来了难以保证。顺便说一句,关于我之前的问题,我在
lazySet
上阅读文档时发现了更多的可疑之处。它指定了一个与volatile write定义完全兼容的操作,但表示“与volatile不同,时效性没有保证”(大意是这样的词)。从这一点可以看出,对于易失性写操作,时效性是有保证的,但事实并非如此。这是一个奇怪的、不成文的、每个人都心照不宣的假设。@MarkoTopolnik谢谢你的提问。对于非k-ish点的用户,如果这会在单线程问题上对hb关系产生任何疑问,我会很长时间感到惊讶