compareAndSwap 普通成员(非易失性成员)仍然具有易失性读写的内存语义

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 class 中,stateOffset 是一个名为 state

的可变成员

只是想知道如果 state 是一个非易失性成员,内存语义是什么..

compareAndSetState() 的语义仍然是可变读写的语义 - 这是 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 必须使用可变读取语义以确保它使用最新值。

是的,原则上您可以拒绝将 state 之类的字段声明为易变的。但是您 必须 确保对该字段的每次访问都经过 compareAndSwapInt()getIntVolatile()putIntVolatile()。如果某些代码维护者忘记了此规则并添加了对该字段的单个直接读取,您的代码将在最不利的时刻以意想不到的方式中断 - 例如,在向重要客户进行演示时。