[英]compareAndSwap a common member ( non-volatile member ) still has memory semantics of volatile read and write
当我在 jdk1.8 中阅读AbstractQueuedSynchronizer
时,我看到compareAndSetState
方法具有易失性读写的内存语义的评论。
注释和代码如下:
/**
* Atomically sets synchronization state to the given updated
* value if the current state value equals the expected value.
* This operation has memory semantics of a {@code volatile} read
* and write.
*/
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
在 AbstractQueuedSynchronizer 类中, stateOffset
是一个名为state
的 volatile 成员
只是想知道如果state
是非易失性成员,内存语义是什么......
compareAndSetState()
的语义仍然是 volatile 读写的语义——这是Unsafe.compareAndSwapInt()
存在的主要原因。
但通常代码不仅仅调用Unsafe.compareAndSwapInt()
。 通常代码读取当前值,计算一个新值,然后尝试用新值替换它读取的值。 而且这种读取也必须使用易失性读取语义来完成。
例如,在CountDownLatch.Sync#tryReleaseShared()
中:
protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } }
使用getState()
读取state
必须使用 volatile 读取语义,以确保它使用最新值。
是的,原则上你可以拒绝将state
这样的字段声明为 volatile。 但是你必须确保对该字段的每次访问都通过compareAndSwapInt()
、 getIntVolatile()
和putIntVolatile()
。 如果代码的某些维护者忘记了此规则并添加了对该字段的单次直接读取,您的代码将在最不利的时刻以意想不到的方式中断 - 例如,在向重要客户进行演示时。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.