1. 程式人生 > >Java原子類實現原理分析

Java原子類實現原理分析

upd hat 16px 檢查 () 過程 jvm api 處理

並發包中的原子類可以解決類似num++這樣的復合類操作的原子性問題,相比鎖機制,使用原子類更精巧輕量,性能開銷更小,下面就一起來分析下原子類的實現機理。

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

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

synchronized(this){
    num++;
 }

  使用獨占鎖機制來解決,是一種悲觀的並發策略,抱著一副“總有刁民想害朕”的態勢,每次操作數據的時候都認為別的線程會參與競爭修改,所以直接加鎖。同一刻只能有一個線程持有鎖,那其他線程就會阻塞。線程的掛起恢復會帶來很大的性能開銷,盡管jvm對於非競爭性的鎖的獲取和釋放做了很多優化,但是一旦有多個線程競爭鎖,頻繁的阻塞喚醒,還是會有很大的性能開銷的

。所以,使用synchronized或其他重量級鎖來處理顯然不夠合理。

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

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

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

技術分享圖片
 /**
     * 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的邏輯:

  1.先獲取當前的value值

  2.對value加一

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

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

  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漏洞。

Java原子類實現原理分析