博客 / 詳情

返回

AbstractQueuedSynchronizer 源碼解析

AbstractQueuedSynchronizer簡稱AQS,ReentrantLock,ReentrantReadWriteLock,CountDownLatch,Semaphore等等這些鎖都是基於AQS實現的。AQS核心主要實現了鎖的狀態的同步,隊列排隊、喚醒管理,鎖的釋放等底層功能。主要基於state屬性來控制鎖的可用狀態,通過維護一個CLH雙向鏈表隊列來管理併發獲取鎖的線程進行排隊。

主要屬性

/**
 * 隊列頭節點,延遲初始化,除了初始化時僅能通過setHead方法修改
 */
private transient volatile Node head;

/**
 * 隊列尾節點,延遲初始化,僅通過enq方法修改添加等待節點
 */
private transient volatile Node tail;

/**
 * 同步器狀態
 */
private volatile int state;

CLH隊列節點屬性

static final class Node {
    /** 共享鎖標記 */
    static final Node SHARED = new Node();
    /** 獨佔鎖標記 */
    static final Node EXCLUSIVE = null;

    /** 節點取消排隊,可能由於超時或者中斷 */
    static final int CANCELLED =  1;
    /** 當前節點的下個節點是阻塞或即將阻塞,當節點釋放鎖或取消時應該喚醒unpark下個節點 */
    static final int SIGNAL    = -1;
    /** 條件隊列節點 */
    static final int CONDITION = -2;
    /**
     * 標識下個節點無條件傳播(適用與共享鎖)
     */
    static final int PROPAGATE = -3;

    //節點等待狀態,0,CANCELLED,SIGNAL,CONDITION,PROPAGATE
    volatile int waitStatus;

    //上個節點
    volatile Node prev;

    //下個節點
    volatile Node next;

    //節點線程
    volatile Thread thread;

    /**
     * 共享鎖時值為 SHARED
     * 條件隊列時指向條件隊列下個節點
     */
    Node nextWaiter;

加鎖流程

image.png

核心方法

//判斷當前請求是否需要排隊
public final boolean hasQueuedPredecessors() {
    Node t = tail;//尾節點
    Node h = head;//頭節點
    Node s;
    return h != t &&//h==t時代表沒有線程排隊,見:java.util.concurrent.locks.AbstractQueuedSynchronizer#enq()
        ((s = h.next) == null || s.thread != Thread.currentThread());
        //
        //s.thread != Thread.currentThread() 判斷第一個排隊線程是否是當前線程
}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.