我理解读取-获取(不对其后的后续读/写操作重新排序)和写-释放(不对其之前的读/写操作重新排序)。 我的问题是:-
- 在读取-获取的情况下,它之前的写入是否被刷新?
- 在写入释放的情况下,之前的读取是否得到更新?
另外,java中read-acquire和volatile read一样,write release和volatile write一样吗?
为什么这很重要,让我们以写释放为例..
y = x; // a read.. let's say x is 1 at this point
System.out.println(y);// 1 printed
//or you can also consider System.out.println(x);
write_release_barrier();
//somewhere here, some thread sets x = 2
ready = true;// this is volatile
System.out.println(y);// or maybe, println(x).. what will be printed?
此时,x是2还是1? 在这里,考虑准备好波动。 我知道 volatile 之前的所有商店都将首先可见..然后只有 volatile 才会可见。谢谢。
引用:- http://preshing.com/20120913/acquire-and-release-semantics/
最佳答案
不:不是所有的写入都被刷新,也不是所有的读取都被更新。
Java 在多线程处理的“先发生”基础上工作。基本上,如果 A happens-before B,B happens-before C,那么 A happens-before C。所以你的问题是 x=2
是否正式 happens-before 一些读取 x 的 Action 。
Happens-before 边基本上是由同步关系建立的,定义在 JLS 17.4.4 中。 .有几种不同的方法可以做到这一点,但对于 volatiles,它基本上相当于写入 volatile happening-before a read to the same volatile:
- A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).
鉴于此,如果您的线程写入 ready = true
,那么单独写入并不意味着在它之前发生任何(就写入而言) .实际上恰恰相反;写入 ready
happens-before things on other threads, iff they read ready
.
因此,如果另一个线程(设置 x = 2
)在设置 x = 2
之后写入就绪 ,这线程(您在上面发布的)然后读取就绪
,然后它会看到x = 2
。那是因为写入发生在读取之前,因此读取线程可以看到写入线程所做的一切(直到并包括写入)。否则,您将面临数据竞争,基本上所有赌注都会落空。
一些补充说明:
- 如果您没有先行发生边缘,您可能仍会看到更新;只是你不能保证。所以,不要假设如果您不读取写入
ready
,那么您仍然会看到 x=1。您可能会看到 x=1 或 x=2,或者可能会看到一些其他写入(直到并包括默认值 x=0) - 在您的示例中,
y
始终为 1,因为您不会在“此处某处”注释后重新阅读x
。出于此答案的目的,我假设在ready = true
之前或之后有第二个y=x
行。如果没有,则 y 的值将与第一个println
中的值保持不变(假设没有其他线程直接更改它——如果它是局部变量,则可以保证),因为线程总是看起来好像没有重新排序。
关于java - Java volatile read flush writes,和volatile write update reads,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35808193/