1. 程式人生 > 實用技巧 >AQS原始碼淺析

AQS原始碼淺析

一、AQS簡介

AbstractQueuedSynchronizer 抽象佇列同步器。簡稱AQS,同時擁有 同步佇列 與 等待佇列

二、原始碼淺析

  1. 同步佇列
執行緒呼叫了lock 方法,首先呼叫 acquire 方法請求鎖,acquire 裡面首先將現場節點封裝Node 加入到同步佇列的隊尾,然後 在 acquireQueued 的迴圈裡面,while 的判斷 是不是head ,是則直接return 說明獲取到鎖,如果不是 則 呼叫了 park 方法阻塞,但是while 迴圈的跳出只能是 當前node 是head 。( 但是前面也說了 head 移除之後會 unpark 後面的結點,並且將後面的setHead) ,所以對於每個在抽象佇列同步器的同步佇列裡面的Node,都是阻塞的,但是同步器每次acquire都會有一個acquireQueued ,相當於每個Node 都會 迴圈的請求,但是迴圈是同步器發出的,類似於一個“自旋”,這個自旋是 同步器控制的,執行緒還是阻塞的。
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

  2. 等待佇列

呼叫 await 方法,進入condition的等待佇列,釋放鎖,進入一個 while 迴圈,只有當執行緒回到同步佇列或者被中斷才可以跳出while,while裡面 park 掉執行緒 ----- 在 condition呼叫 signal 之後,該condition上面的節點的 firstWaiter 首先加入到 同步佇列尾部 , 會 unpark 執行緒,退出 while 之後,又會進入 acquireQueued 的迴圈裡面,同樣存在之前的邏輯。

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

  3. 總結

    • 等待佇列,是已經獲取到鎖的執行緒,需要用到其他執行緒的資料,主動呼叫 wait() 方法,並且釋放鎖,喚醒同步佇列的後繼節點(非公平不用喚醒),然後當前節點構造新的Node進入等待佇列,當有其他 在同步佇列裡面 已經獲得鎖的執行緒呼叫 notify()(或者 signal())之後,才會重新加入同步佇列,嘗試獲取鎖。 等待佇列的節點也呼叫了 park () 方法阻塞。
    • Condition 介面中的 await() 與 signal() 函式分別用於 是執行緒進行等待狀態---加入到等待佇列中 、喚醒等待佇列中的首節點的執行緒。
    • 在ReetrantLock 裡面,公平與非公平自旋鎖,也是基於 同步器的,同步器的佇列是預設阻塞的 ,ReetrantLock 裡面是自旋非阻塞的。compareAndSetState
    • ReetrantLock 裡面 公平與非公平的自旋鎖,都是在一直自旋沒有 park(), 公平多了一個判斷當前節點是否有前驅節點語句
      if (!hasQueuedPredecessors()...

三、工具類

  • LockSupport
定義了一系列的公有靜態方法,用於 阻塞&&喚醒 一個執行緒。 LockSupport 中的park 與 unpark 等方法,最終都是呼叫的 Unsafe 類中的方法,而 Unsafe 類中提供的是一系列的硬體級別的原子操作 ,有點類似於 彙編級別或者機器碼級別 指令一樣

轉載請註明地址:https://www.cnblogs.com/handsomecui/p/14253284.html