天天看点

Java源码分析-原子操作类Atomic

原子操作类主要有:

AtomicLong                       AtomicInteger                       AtomicReference                          AtomicBoolean

AtomicLongArray              AtomicIntegerArray               AtomicReferenceArray

AtomicLongFieldUpdater  AtomicIntegerFieldUpdater   AtomicReferenceFieldUpdater

看一下AtomicLong的源码

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

    // 获取Unsafe对象,下面的原子操作都是基于unsafe对象的CompareAndSet()方法
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // 偏移值
    private static final long valueOffset;

    // 虚拟机是否支持对long型的CAS无锁算法
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

    // 返回底层的结果
    private static native boolean VMSupportsCS8();

    // 获取偏移值
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicLong.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    // 定义为valatile的long型值,AtomicLong的值保存的地方
    private volatile long value;

    // 初始化value
    public AtomicLong(long initialValue) {
        value = initialValue;
    }

    public AtomicLong() {
    }

    // 获取当前值
    public final long get() {
        return value;
    }

    // 设置值
    public final void set(long newValue) {
        value = newValue;
    }

    // 最终设置为新的值,刚调用完这个方法后可能不会马上生效,其他线程可能在一小段时间内还是会读到    
    // 旧值,但最终是设置为新值
    public final void lazySet(long newValue) {
        unsafe.putOrderedLong(this, valueOffset, newValue);
    }

    // 以原子的方式设置新值,返回旧值
    public final long getAndSet(long newValue) {
        return unsafe.getAndSetLong(this, valueOffset, newValue);
    }

    // 以原子的方式用当前值与expect值,如果相同就设置新值为update,并返回true,否则返回false
    public final boolean compareAndSet(long expect, long update) {
        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    }

    // 和上面的方法实现一致
    public final boolean weakCompareAndSet(long expect, long update) {
        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    }

    // 以原子的方式把值+1,然后返回之前的值
    public final long getAndIncrement() {
        return unsafe.getAndAddLong(this, valueOffset, 1L);
    }

    // 以原子的方式把值-1,然后返回之前的值
    public final long getAndDecrement() {
        return unsafe.getAndAddLong(this, valueOffset, -1L);
    }

    // 以原子的方式把值+delta,然后返回之前的值
    public final long getAndAdd(long delta) {
        return unsafe.getAndAddLong(this, valueOffset, delta);
    }

    // 以原子的方式把值+1,然后返回+1后的值
    public final long incrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
    }

    // 以原子的方式把值-1,然后返回-1后的值
    public final long decrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
    }

    // 以原子的方式把值+delta,然后返回最新值
    public final long addAndGet(long delta) {
        return unsafe.getAndAddLong(this, valueOffset, delta) + delta;
    }

    /**
     * 原子的更新value并返回旧值
     * jdk8才有的,可通过lambda表达式传入参数
     * The function should be side-effect-free, since it may be re-applied
     * when attempted updates fail due to contention among threads.
     *
     * @param updateFunction a side-effect-free function
     * @return the previous value
     * @since 1.8
     */
    public final long getAndUpdate(LongUnaryOperator updateFunction) {
        long prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsLong(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function, returning the updated value. The
     * function should be side-effect-free, since it may be re-applied
     * when attempted updates fail due to contention among threads.
     *
     * @param updateFunction a side-effect-free function
     * @return the updated value
     * @since 1.8
     */
    public final long updateAndGet(LongUnaryOperator updateFunction) {
        long prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsLong(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function to the current and given values,
     * returning the previous value. The function should be
     * side-effect-free, since it may be re-applied when attempted
     * updates fail due to contention among threads.  The function
     * is applied with the current value as its first argument,
     * and the given update as the second argument.
     *
     * @param x the update value
     * @param accumulatorFunction a side-effect-free function of two arguments
     * @return the previous value
     * @since 1.8
     */
    public final long getAndAccumulate(long x,
                                       LongBinaryOperator accumulatorFunction) {
        long prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsLong(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * Atomically updates the current value with the results of
     * applying the given function to the current and given values,
     * returning the updated value. The function should be
     * side-effect-free, since it may be re-applied when attempted
     * updates fail due to contention among threads.  The function
     * is applied with the current value as its first argument,
     * and the given update as the second argument.
     *
     * @param x the update value
     * @param accumulatorFunction a side-effect-free function of two arguments
     * @return the updated value
     * @since 1.8
     */
    public final long accumulateAndGet(long x,
                                       LongBinaryOperator accumulatorFunction) {
        long prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsLong(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

    public String toString() {
        return Long.toString(get());
    }
    public int intValue() {
        return (int)get();
    }
    public long longValue() {
        return get();
    }
    public float floatValue() {
        return (float)get();
    }
    public double doubleValue() {
        return (double)get();
    }
           

Array类的和上面的实现差不多,就不写出来了,看一下另外一个:AtomicLongFieldUpdater 

这个是对指定类的指定的volatile long的字段实现原子操作

AtomicLongFieldUpdater atomicLongFieldUpdater = AtomicLongFieldUpdater.newUpdater(Person.class, "id");
Person p1 = new Person(1);
Person p2 = new Person(2);
atomicLongFieldUpdater.addAndGet(p1, 4);
System.out.println(p1);// id = 5
atomicLongFieldUpdater.compareAndSet(p2, 2, 10);
System.out.println(p2);// id = 10

    class Person {
        volatile long id;

        public Person(long id) {
            this.id = id;
        }
        public long getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "id = " + this.id;
        }
    }
           
AtomicLongFieldUpdater是一个抽象类,通过newUpdater来构造一个对象实例
           
@CallerSensitive
    public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
                                                           String fieldName) {
        Class<?> caller = Reflection.getCallerClass();
        if (AtomicLong.VM_SUPPORTS_LONG_CAS)
            return new CASUpdater<U>(tclass, fieldName, caller);
        else
            return new LockedUpdater<U>(tclass, fieldName, caller);
    }
           

为了防止CAS的ABA问题,jdk又提供了AtomicStamedReference类,这个类在操作实例引用的时候加入了一个戳记,根据戳记可以防止ABA问题。

AtomicStampedReference atomicStampedReference = new AtomicStampedReference(p1, 10000);
int oldStamp = atomicStampedReference.getStamp();
int newStamp = 20000;
// 把引用对象由p1替换为p2
boolean f = atomicStampedReference.compareAndSet(p1, p2, oldStamp, newStamp);
System.out.println(f);// true
System.out.println(p1);//1
System.out.println(p2);//2
// getReference()得到的是p2的引用
Person p3 = (Person) atomicStampedReference.getReference();
System.out.println(p1);//1
System.out.println(p2);//2
System.out.println(p3);//2
System.out.println(p1 == p3);//false
System.out.println(p2 == p3);//true
           

看下AtomicStamedReference的源码

package java.util.concurrent.atomic;

public class AtomicStampedReference<V> {
    // 内置了Pair类,保存引用和戳记
    private static class Pair<T> {
        final T reference;
        final int stamp;
        private Pair(T reference, int stamp) {
            this.reference = reference;
            this.stamp = stamp;
        }
        // 新建一个Pair
        static <T> Pair<T> of(T reference, int stamp) {
            return new Pair<T>(reference, stamp);
        }
    }

    private volatile Pair<V> pair;

    // 构造函数,创建AtomicStampedReference
    public AtomicStampedReference(V initialRef, int initialStamp) {
        pair = Pair.of(initialRef, initialStamp);
    }

    // 返回当前的引用
    public V getReference() {
        return pair.reference;
    }

    // 返回当前的戳记
    public int getStamp() {
        return pair.stamp;
    }

    // 返回当前的引用和戳记(放数组第一个元素里)
    public V get(int[] stampHolder) {
        Pair<V> pair = this.pair;
        stampHolder[0] = pair.stamp;
        return pair.reference;
    }

    // 设置newReference替换expectedReference
    public boolean weakCompareAndSet(V   expectedReference,
                                     V   newReference,
                                     int expectedStamp,
                                     int newStamp) {
        return compareAndSet(expectedReference, newReference,
                             expectedStamp, newStamp);
    }

    // 设置newReference替换expectedReference
    // 除了传入期待的引用还要传入期待的戳记
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        // 期待的与当前的 引用和戳记都要相等 并且
        // 新引用和新戳记都等于当前的(相当于没有set新引用) 或者 (如果要设置新引用的情况下)当前 
        // Pari(this)与期待的pair(current) 相同
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));//CAS
    }

    // 无条件的设置新的引用和戳记
    public void set(V newReference, int newStamp) {
        Pair<V> current = pair;
        if (newReference != current.reference || newStamp != current.stamp)
            this.pair = Pair.of(newReference, newStamp);
    }

    // 原子的设置新的戳记
    public boolean attemptStamp(V expectedReference, int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            (newStamp == current.stamp ||
             casPair(current, Pair.of(expectedReference, newStamp)));
    }

    // Unsafe mechanics

    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
    private static final long pairOffset =
        objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);

    private boolean casPair(Pair<V> cmp, Pair<V> val) {
        return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
    }

    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
                                  String field, Class<?> klazz) {
        try {
            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
        } catch (NoSuchFieldException e) {
            // Convert Exception to corresponding Error
            NoSuchFieldError error = new NoSuchFieldError(field);
            error.initCause(e);
            throw error;
        }
    }
}
           

注:以上JDK8的新方法,待以后再补充