高併發程式設計-AQS深入解析

mpsky發表於2021-09-09

要點解說

AbstractQueuedSynchronizer簡稱AQS,它是java.util.concurrent包下CountDownLatch/FutureTask/ReentrantLock/RenntrantReadWriteLock/Semaphore實現的基礎,所以深入理解AQS非常有必要。

AQS透過內部實現的FIFO同步等待佇列來完成資源獲取執行緒的等待工作,如果當前執行緒獲取資源失敗,AQS則會將當前執行緒以及等待狀態等資訊構造成一個Node結構的節點,並將其加入等待佇列中,同時會阻塞當前執行緒;當其它獲取到資源的執行緒釋放持有的資源時,則會把等待佇列節點中的執行緒喚醒,使其再次嘗試獲取對應資源。

原始碼解析

AbstractQueuedSynchronizer原始碼比較長,這裡只分析主要的功能程式碼。首先,先看一下它內部定義的Node類的程式碼。

static  final class Node {       //宣告共享模式下的等待節點

       static final Node SHARED = new Node();        





       //宣告獨佔模式下的等待節點

       static final Node EXCLUSIVE = null;        





       //waitStatus的一常量值,表示執行緒已取消

       static final int CANCELLED =  1;        





       //waitStatus的一常量值,表示後繼執行緒需要取消掛起

       static final int SIGNAL    = -1;        





       //waitStatus的一常量值,表示執行緒正在等待條件

       static final int CONDITION = -2;        





       //waitStatus的一常量值,表示下一個acquireShared應無條件傳播

       static final int PROPAGATE = -3;        





       //waitStatus,其值只能為CANCELLED、SIGNAL、CONDITION、PROPAGATE或0

       //初始值為0

       volatile int waitStatus;        





       //前驅節點

       volatile Node prev;        





       //後繼節點

       volatile Node next;        





       //當前節點的執行緒,在節點初始化時賦值,使用後為null

       volatile Thread thread;        





       //下一個等待節點

       Node nextWaiter;
        





       Node() {

       }
        





       Node(Thread thread, Node mode) {    

           // Used by addWaiter

           this.nextWaiter = mode;           this.thread = thread;

       }
        





       Node(Thread thread, int waitStatus) {           // Used by Condition

           this.waitStatus = waitStatus;           this.thread = thread;

       }

   }

上面的Node就是等待佇列裡的一個節點,具體結構如下:

圖片描述

image

接著,來看一下AbstractQueuedSynchronizer的三個重要屬性:

  
   //等待佇列的頭結點

    private transient volatile Node head;    //等待佇列的尾節點

    private transient volatile Node tail;    //同步狀態,這個很重要

    private volatile int state;

從這就可以得到同步佇列的基本結構:

圖片描述

image

同時,同步器中提供了三個方法用於操作同步狀態:

    protected final int getState() {        return state;

    }    





    protected final void setState(int newState) {

        state = newState;

    }    





    //使用CAS設定同步狀態,確保執行緒安全

    protected final boolean compareAndSetState(int expect, int update) {        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);

    }

AbstractQueuedSynchronizer類中其它方法主要是用於插入節點、釋放節點,插入節點過程如下圖所示:

圖片描述

image

釋放頭結點過程如下圖所示:

圖片描述

image

分析小結

AbstractQueuedSynchronizer實現了對資源獲取與釋放的基礎實現,真正使用到的地方還在是各個具體的功能類中,如CountDownLatch、ReentrantLock等,後面在這些類中會具體分析。

面試考點

AQS是什麼?內部實現結構瞭解嗎? AbstractQueuedSynchronizer簡稱AQS,它為實現依賴於先進先出 (FIFO) 等待佇列的阻塞鎖和相關同步器(訊號量等)提供一個基礎實現框架。內部實現結構參考上面的圖示作答。



作者:JavaQ
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1806/viewspace-2818740/,如需轉載,請註明出處,否則將追究法律責任。

相關文章