AQS原始碼淺析
阿新 • • 發佈:2021-01-08
一、AQS簡介
AbstractQueuedSynchronizer 抽象佇列同步器。簡稱AQS,同時擁有 同步佇列 與 等待佇列
二、原始碼淺析
- 同步佇列
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