java原始碼-AtomicReference

晴天哥發表於2018-08-10

開篇

 The AtomicReference class provides reference objects that may be read and written atomically, so when multiple threads try to reach them at the same time, only one will be able to do so.
換句話說就是AtomicReference提供Object物件的原子類操作,提供了更加靈活的操作

AtomicReference類和構造器

 AtomicReference的建構函式類構造器有兩個:

  • 無參建構函式採用預設值初始化為0
  • 有引數建構函式直接用initialValue來value的

 AtomicReference類變數需要注意的兩個點:

  • AtomicReference的關鍵邏輯在於static程式碼快中通過unsafe介面初始化value的記憶體地址,後續直接通過記憶體地址進行操作。
  • AtomicReference的value是用volatile進行修飾保證變數的可見性
public class AtomicReference<V> implements java.io.Serializable {
    private static final long serialVersionUID = -1848883965231344442L;

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    // 儲存AtomicLong中value的記憶體地址便於快速操作
    private static final long valueOffset;
    
    // 獲取value的記憶體地址的邏輯操作
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicReference.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile V value;
    
    // 以傳入的initialValue初始化value物件
    public AtomicReference(V initialValue) {
        value = initialValue;
    }

    // 以傳入的null初始化value物件
    public AtomicReference() {
    }
}

AtomicReference的get操作

 AtomicReference的get操作相比之前的AtomicLong的get操作少了getAndIncrement()等自增自減的操作,只支援整個物件的更新。

  • getAndSet()方法取出原來的值並更新新值newValue
  • getAndUpdate()、getAndAccumulate()等操作通過compareAndSet()操作完成原子性的物件更新
    public final V get() {
        return value;
    }


    @SuppressWarnings("unchecked")
    public final V getAndSet(V newValue) {
        return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
    }

    public final V getAndUpdate(UnaryOperator<V> updateFunction) {
        V prev, next;
        do {
            prev = get();
            next = updateFunction.apply(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    public final V getAndAccumulate(V x,
                                    BinaryOperator<V> accumulatorFunction) {
        V prev, next;
        do {
            prev = get();
            next = accumulatorFunction.apply(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

AtomicReference的set操作

 AtomicReference的set操作是通過unsafe.compareAndSwapObject()方法實現原子性操作,updateAndGet()方法只有在原子性更新成功後才能返回更新後的物件。


    public final void set(V newValue) {
        value = newValue;
    }

    public final void lazySet(V newValue) {
        unsafe.putOrderedObject(this, valueOffset, newValue);
    }

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

    public final boolean weakCompareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

    public final V updateAndGet(UnaryOperator<V> updateFunction) {
        V prev, next;
        do {
            prev = get();
            next = updateFunction.apply(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    public final V accumulateAndGet(V x,
                                    BinaryOperator<V> accumulatorFunction) {
        V prev, next;
        do {
            prev = get();
            next = accumulatorFunction.apply(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

案例

// AtomicReferenceTest.java的原始碼
import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceTest {
    
    public static void main(String[] args){

        // 建立兩個Person物件,它們的id分別是101和102。
        Person p1 = new Person(101);
        Person p2 = new Person(102);
        // 新建AtomicReference物件,初始化它的值為p1物件
        AtomicReference ar = new AtomicReference(p1);
        // 通過CAS設定ar。如果ar的值為p1的話,則將其設定為p2。
        ar.compareAndSet(p1, p2);

        Person p3 = (Person)ar.get();
        System.out.println("p3 is "+p3);
        System.out.println("p3.equals(p1)="+p3.equals(p1));
    }
}

class Person {
    volatile long id;
    public Person(long id) {
        this.id = id;
    }
    public String toString() {
        return "id:"+id;
    }
}

執行結果
p3 is id:102
p3.equals(p1)=false

文末彩蛋

高手是持續性自律,你是間歇式自虐

對高手而言

自律是一種生活方式

若只是間歇性的熱血沸騰

不可能成功

很多工作拼的不是才華

而是持續和穩定

所以先把你的勤奮變成現在進行時吧!

剔除自我感動,也學會自我成全

工作、程式碼、寫作、跑步,近乎苦行僧般的生活讓我感到很踏實


相關文章