考虑一个简单的单线程Java程序执行,它不涉及同步操作,只是实例变量的简单读写.简单地忽略所有写入的实现似乎符合Java内存规范.首先,§17.4适用的一般声明:
内存模型确定可以在程序中的每个点读取哪些值.隔离中每个线程的操作必须遵循该线程的语义,除了每次读取所看到的值由内存模型确定.
相关的限制因素如下(第17.4.5节):
如果x和y是同一个线程的动作,并且x在程序顺序中出现在y之前,那么hb(x,y).
如果对于A中的所有读取r,其中W(r)是r看到的写入动作,那么一组动作A发生 - 在一致之前,不是hb(r,W(r))或那里的情况在A中存在写w,使得wv = rv和hb(W(r),w)和hb(w,r).
这基本上排除了在它观察到的写入之前发生的读取.另一个条款只是一个完整性条款,它可以防止某些人v看到之前写的那篇内容,v然后又写了一篇同样的内容v.
我无法保证可以正确地观察到写入,只能限制对写入的内容.
我在这里错过了什么?JVM是否真的可以省略这样一个微不足道的保证?
让我们使用:
\n\nclass MyClass {\n private static int i = 0;\n\n public static void main(String[] args) {\n i = 3; //w\n System.out.println(i); //r\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n当程序包含两个不按先发生关系排序的冲突访问 (\xc2\xa717.4.1) 时,称其包含数据争用。
\n\n您的程序是单线程的
\n=> 我们从程序顺序约束中得到 hb(w,r)
\n=> 它已正确同步
\n=> 程序的所有执行将显示为顺序一致。
\n=> 它将打印 3