原子類包分析實現

文章目錄

atomic包

在這裏插入圖片描述

java.util.concurrent.atomic包下的類大多是使用CAS操作來實現的(eg. AtomicInteger.java,AtomicBoolean,AtomicLong)。下面以 AtomicInteger.java的部分實現來大致講解下這些原子類的實現。
它提供了原子自增方法、原子自減方法以及原子賦值方法等



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 volatile int value;// 初始int大小
    // 省略了部分代碼...

    // 帶參數構造函數,可設置初始int大小
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
    // 不帶參數構造函數,初始int大小爲0
    public AtomicInteger() {
    }

    // 獲取當前值
    public final int get() {
        return value;
    }

    // 設置值爲 newValue
    public final void set(int newValue) {
        value = newValue;
    }

    //返回舊值,並設置新值爲 newValue
    public final int getAndSet(int newValue) {
        /**
        * 這裏使用for循環不斷通過CAS操作來設置新值
        * CAS實現和加鎖實現的關係有點類似樂觀鎖和悲觀鎖的關係
        * */
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }

    // 原子的設置新值爲update, expect爲期望的當前的值
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    // 獲取當前值current,並設置新值爲current+1
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }

    // 此處省略部分代碼,餘下的代碼大致實現原理都是類似的
}


一般來說在競爭不是特別激烈的時候,使用該包下的原子操作性能比使用 synchronized 關鍵字的方式高效的多(查看getAndSet(),可知如果資源競爭十分激烈的話,這個for循環可能換持續很久都不能成功跳出。不過這種情況可能需要考慮降低資源競爭纔是)。
在較多的場景我們都可能會使用到這些原子類操作。一個典型應用就是計數了,在多線程的情況下需要考慮線程安全問題。通常第一映像可能就是:

public class Counter {
///這個版本是線程安全的
    private int count;
    public Counter(){}
    public int getCount(){
        return count;
    }
    public void increase(){
        count++;
    }
}

上面這個類在多線程環境下會有線程安全問題,要解決這個問題最簡單的方式可能就是通過加鎖的方式,調整如下:

public class Counter {
    private int count;
    public Counter(){}
    public synchronized int getCount(){
        return count;
    }
    public synchronized void increase(){
        count++;
    }
}


這類似於悲觀鎖的實現,我需要獲取這個資源,那麼我就給他加鎖,別的線程都無法訪問該資源,直到我操作完後釋放對該資源的鎖。我們知道,悲觀鎖的效率是不如樂觀鎖的,上面說了Atomic下的原子類的實現是類似樂觀鎖的,效率會比使用 synchronized 關係字高,推薦使用這種方式,實現如下:


public class Counter {
    private AtomicInteger count = new AtomicInteger();
    public Counter(){}
    public int getCount(){
        return count.get();
    }
    public void increase(){
        count.getAndIncrement();
    }
}



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