我试着理解为什么这个例子是一个正确同步的程序:
a - volatile
Thread1:
x=a
Thread2:
a=5
因为存在冲突的访问(存在对a的写入和读取)所以在每个顺序一致性执行中必须发生 - 在该访问之间的关系之前。 假设一个顺序执行:
1. x=a
2. a=5
1发生在2之前,为什么?
我试着理解为什么这个例子是一个正确同步的程序:
a - volatile
Thread1:
x=a
Thread2:
a=5
因为存在冲突的访问(存在对a的写入和读取)所以在每个顺序一致性执行中必须发生 - 在该访问之间的关系之前。 假设一个顺序执行:
1. x=a
2. a=5
1发生在2之前,为什么?
不,之前的(以同步顺序)易失性读取不一定是相同变量的易失性写入 之前发生 易变写。
这意味着它们可以处于“数据竞争”中,因为它们是“冲突的访问,而不是由先发生过的关系命令”。如果这是真的,几乎所有程序都包含数据竞争:)但它可能是一个规范错误。永远不应将易失性读写视为数据竞争。如果程序中的所有变量都是易失性的,则所有执行都是顺序一致的。看到 http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html
如果你有一个volatile变量 a
并且一个线程正在从中读取而另一个线程正在写入它,这些访问的顺序可以是 或 订购。它是一个 竞争条件。这取决于首先启动的操作。
写入可能刚刚发生,读取看到更新的值。或者写入可能在读取之后发生。所以 x
可能是 5
或以前的值 a
。
每个顺序一致性执行必须在该访问之间的关系之前发生
你在这里误导了。 “关系发生之前” volatile
表示先前所有先前的内存更新 或 读或写 volatile
变量保证已完成。所以两个线程都有“发生之前”的保证,但这并不能解释两者如何 volatile
访问互动。这取决于竞争条件。读者保证已经看过写, 但 只有在写入发生在读取之前。
易失性和发生之前仅在读取字段驱动某些条件时才有用。例如:
volatile int a;
int b =0;
Thread-1:
b = 5;
a = 10;
Thread-2
c = b + a;
在这种情况下,没有发生 - 之前,a可以是10或0,b可以是5或0,因此结果c可以是0,5,10或15.如果读取a意味着其他一些条件然后发生before-before例如:
int b = 0;
volatile int a = 0;
Thread-1:
b = 5
a = 10;
Thread 2:
if(a == 10){
c = b + a;
}
在这种情况下,您将确保c = 15,因为读取 a==10
暗示写的 b = 5
在写之前发生 a = 10
编辑:更新添加顺序,如灰色所示的不一致
抱歉,您无法正确说出JVM如何根据JVM的“内存模型”优化代码。您必须使用Java的高级工具来定义您想要的内容。
所以volatile只意味着没有用于变量的“线程间缓存”。
如果您想要更严格的订单,则必须使用同步块。
http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html