AtomicInteger

AtomicIntegerAtomicLong、及 AtomicReference 的实现类似,这里以 AtomicInteger 为例。

成员变量

AtomicInteger 类的整体结构如下:

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe(); // ①
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value")); // ②
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile int value; // ③

    //...
}

要点说明如下:

  • ① 处调用 Unsafe.getUnsafe 获取 Unsafe 实例,该方法在 JUC 中将多次出现
  • ② 处获取了 ③ 中定义的 value 字段对应的偏移量,后续调用 Unsafe 方法时使用
  • ③ 中定义了保存数据的 value 字段,注意它声明的是 volatile

我们知道 Unsafe::compareAndSwapInt 方法是保证了有序性与可见性的,那么 value 为什么还要声明成 volatile?这里因为除了 CAS 相关的方法, AtomicInteger 还提供了诸如 get/set 方法,这些方法需要变量是 volatile 才能保证有序性与可见性。

getAndSet

getAndSet 用于获取旧的值,并设置成新的值,要注意这个方法在执行时会“自旋”,即轮询直到设置成功。源码如下:

public final int getAndSet(int newValue) {
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}

其中 unsafe.getAndSetInt 的实现如下:

public final int getAndSetInt(Object o, long offset, int newValue) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, newValue));
    return v;
}

这里用 getIntVolatile 保证读取的是最新的值,之后用 compareAndSwapInt 来替换成新的值。这里的自旋+获取旧值+设置新值,也是 CAS 的最典型的使用方式。

compareAndSet

compareAndSet 只是简单封装了 unsafe.compareAndSwapInt,如果当前值等于expect,将值设置为新值 update

public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

lazySet

这个方法是 unsafe.putOrderedInt 的封装,在 Unsafe 一章中说过,它保证有序性,但不保证可见性(修改立即对其它线程可见),因此性能更高。

public final void lazySet(int newValue) {
    unsafe.putOrderedInt(this, valueOffset, newValue);
}

weakCompareAndSet

这是一个预留的方法,对它的预期是可能因为示知原因而失败,且不保证有序性。不过看到当前的实现与 compareAndSet 一模一样。

/**
 * <p><a href="package-summary.html#weakCompareAndSet">May fail
 * spuriously and does not provide ordering guarantees</a>, so is
 * only rarely an appropriate alternative to {@code compareAndSet}.
 */
public final boolean weakCompareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

VMSupportsCS8

AtomicLong 中还有一个特殊的变量和方法,用来判断当前 JVM 是否支持 8 字节(long 型)的 CAS 操作,这个方法在 Updater 中会用到。

private static native boolean VMSupportsCS8();

static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();