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的新方法,待以後再補充

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章