Java 源码 - java.util.concurrent.atomic.AtomicLong

150 阅读2分钟

概述

AtomicLong 是一个 Java concurrent 包提供的一个原子类,通过这个类可以对 Long 进行一些原子操作。这个类的源码比较简单,主要是依赖于 sun.misc.Unsafe 提供的一些 native 方法保证操作的原子性。基本操作和方法与AtomicInteger类似,大家可以参考之前的AtomicInteger的文章

继承关系

public class AtomicLong extends Number implements java.io.Serializable 

成员属性

    // setup to use Unsafe.compareAndSwapLong for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    private volatile long value;

    /**
     * Records whether the underlying JVM supports lockless
     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
     * method works in either case, some constructions should be
     * handled at Java level to avoid locking user-visible locks.
     */
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

    /**
     * Returns whether underlying JVM supports lockless CompareAndSet
     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
     */
    private static native boolean VMSupportsCS8();

记录底层JVM是否支持longs的无锁compareAndSwap。 虽然Unsafe.compareAndSwapLong方法在任何一种情况下都可以工作, 但是应该在Java级别处理一些构造以避免锁定用户可见的锁。而VMSupportsCS8() 方法返回底层JVM是否支持longs的无锁CompareAndSet。 仅调用一次并缓存在VM_SUPPORTS_LONG_CAS中

静态代码块

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

基本方法

与AtomicInteger类似,只是在调用unsafe对象的方法时,调用compareAndSwapLong() 方法,例如

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

该方法时基于CAS

其CAS源码核心代码为:

1
2
3
4
5
6
7
8
9
`int` `compare_and_swap (``int``* reg,` `int` `oldval,` `int` `newval)`
`{`
`ATOMIC();`
`int` `old_reg_val = *reg;`
`if` `(old_reg_val == oldval)`
`*reg = newval;`
`END_ATOMIC();`
`return` `old_reg_val;`
`}`

虚拟机指令为:

1
2
3
4
`mov` `0xc``(%r11),%eax ; Load`
`mov %eax,%r8d`
`inc %r8d ; Increment`
`lock cmpxchg %r8d,``0xc``(%r11) ; Compare and exchange`

因为CAS是基于乐观锁的,也就是说当写入的时候,如果寄存器旧值已经不等于现值,说明有其他CPU在修改,那就继续尝试。所以这就保证了操作的原子性。