当使用例如AtomicInteger时,getVolatile
与getAcquire之间有什么区别?
PS:它们与
同步边的源称为“释放”,目标称为“获取”。
来自https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.3
当使用例如AtomicInteger时,getVolatile
与getAcquire之间有什么区别?
PS:它们与
同步边的源称为“释放”,目标称为“获取”。
来自https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.3
getAquire
确保在其后执行的指令不会在它之前执行。这些指令可能会被重新排序,但它们将始终在 getAquire
之后执行。setRelease
(对于 VarHandle
)结合使用。其中 setRelease
确保在它之前发生的事情不会被重新排序为在它之后发生。Thread1:
var x = 1;
var y = 2;
var z = 3;
A.setRelease(this, 10)
x、y和z的分配将在A.setRelease之前发生,但它们本身可能会被重新排序。
Thread 2:
if (A.getAquire(this) == 10) {
// we know that x is 1, y is 2 and z = 3
}
这是一个很好的并发程序用例,您不需要在所有地方都使用volatile,只需要在某些指令执行之前执行一些指令即可。
对于getVolatile
,该变量被视为Java中的任何volatile变量。没有重新排序或优化发生。
这个视频是一个很好的了解所谓的“内存排序模式”(plain、opaque、release/acquire和volatile)的方式。
获取/释放(acquire/release)和易失性(顺序一致性)之间的关键区别可以通过使用Dekker算法来演示。
public void lock(int t) {
int other = 1-t;
flag[t]=1
while (flag[other] == 1) {
if (turn == other) {
flag[t]=0;
while (turn == other);
flag[t]=1
}
}
}
public void unlock(int t) {
turn = 1-t;
flag[t]=0
}
假设使用 release 存储来编写标志并使用 acquire-load 来加载标志,那么我们将获得以下排序保证:
.. other loads/stores
[StoreStore][LoadStore]
flag[t]=1 // release-store
flag[other] // acquire-load
[LoadLoad][LoadStore]
.. other loads/stores
.. other loads/stores
[StoreStore][LoadStore]
flag[t]=1 // release-store
[StoreLoad]
flag[other] // acquire-load
[LoadLoad][LoadStore]
.. other loads/stores
在ARM上,这是在读取端完成的。需要使用LDAR而不是较弱的LDAPR,这将导致LDAR等待直到存储缓冲区中的STLR已排空。
要深入了解,请查看以下链接:https://shipilev.net/blog/2014/on-the-fence-with-dependencies/
IRIW
可视化...也许我受到Shipilev演示之一的影响。 - Eugene