Java原子類實現原理分析

在談談java中的volatile一文中,咱們提到過併發包中的原子類能夠解決相似num++這樣的複合類操做的原子性問題,相比鎖機制,使用原子類更精巧輕量,性能開銷更小,本章就一塊兒來分析下原子類的實現機理。
java

悲觀的解決方案(阻塞同步)

咱們知道,num++看似簡單的一個操做,其實是由1.讀取 2.加一 3.寫入 三步組成的,這是個複合類的操做(因此咱們以前提到過的volatile是沒法解決num++的原子性問題的),在併發環境下,若是不作任何同步處理,就會有線程安全問題。最直接的處理方式就是加鎖算法

synchronized(this){
    num++;
 }

使用獨佔鎖機制來解決,是一種悲觀的併發策略,抱着一副「總有刁民想害朕」的態勢,每次操做數據的時候都認爲別的線程會參與競爭修改,因此直接加鎖。同一刻只能有一個線程持有鎖,那其餘線程就會阻塞。線程的掛起恢復會帶來很大的性能開銷,儘管jvm對於非競爭性的鎖的獲取和釋放作了不少優化,可是一旦有多個線程競爭鎖,頻繁的阻塞喚醒,仍是會有很大的性能開銷的。因此,使用synchronized或其餘重量級鎖來處理顯然不夠合理。安全

樂觀的解決方案(非阻塞同步)

樂觀的解決方案,顧名思義,就是很大度樂觀,每次操做數據的時候,都認爲別的線程不會參與競爭修改,也不加鎖。若是操做成功了那最好;若是失敗了,好比中途確有別的線程進入並修改了數據(依賴於衝突檢測),也不會阻塞,能夠採起一些補償機制,通常的策略就是反覆重試。很顯然,這種思想相比簡單粗暴利用鎖來保證同步要合理的多。併發

鑑於併發包中的原子類其實現機理都差不太多,本章咱們就經過AtomicInteger這個原子類來進行分析。咱們先來看看對於num++這樣的操做AtomicInteger是如何保證其原子性的。app

 /**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

咱們來分析下incrementAndGet的邏輯:jvm

1.先獲取當前的value值ide

2.對value加一性能

3.第三步是關鍵步驟,調用compareAndSet方法來來進行原子更新操做,這個方法的語義是:優化

先檢查當前value是否等於current,若是相等,則意味着value沒被其餘線程修改過,更新並返回true。若是不相等,compareAndSet則會返回false,而後循環繼續嘗試更新。this

  compareAndSet調用了Unsafe類的compareAndSwapInt方法

/**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

Unsafe的compareAndSwapInt是個native方法,也就是平臺相關的。它是基於CPU的CAS指令來完成的。

    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

CAS(Compare-and-Swap)  

CAS算法是由硬件直接支持來保證原子性的,有三個操做數:內存位置V、舊的預期值A和新值B,當且僅當V符合預期值A時,CAS用新值B原子化地更新V的值,不然,它什麼都不作。

CAS的ABA問題

固然CAS也並不完美,它存在」ABA」問題,倘若一個變量初次讀取是A,在compare階段依然是A,但其實可能在此過程當中,它先被改成B,再被改回A,而CAS是沒法意識到這個問題的。CAS只關注了比較先後的值是否改變,而沒法清楚在此過程當中變量的變動明細,這就是所謂的ABA漏洞。

相關文章
相關標籤/搜索