上篇博客稍微介紹了一下AQS,下面我們來關注下AQS的所獲取和鎖釋放。
AQS鎖獲取
AQS包含如下幾個方法:
acquire(int arg):以獨占模式獲取對象,忽略中斷。
acquireInterruptibly(int arg): 以獨占模式獲取對象,如果被中斷則中止。
acquireShared(int arg): 以共享模式獲取對象,忽略中斷。
acquireSharedInterruptibly(int arg)以共享模式獲取對象,如果被中斷則中止。
tryAcquire(int arg):試圖在獨占模式下獲取對象狀態。
tryAcquireNanos(int arg, long nanosTimeout):試圖以獨占模式獲取對象,如果被中斷則中止,如果到了給定超時時間,則會失敗。
tryAcquireShared(int arg):試圖在共享模式下獲取對象狀態。
tryAcquireSharedNanos(int arg, long nanosTimeout):試圖以共享模式獲取對象,如果被中斷則中止,如果到了給定超時時間,則會失敗。
對於lock.lock()最終都會調用AQS的acquire()方法,Semaphore.acquire()最終會調用AQS的acquireSharedInterruptibly()方法,其中acquire()源代碼如下:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
tryAcquire:去嘗試獲取鎖,獲取成功則設置鎖狀態並返回true,否則返回false。
addWaiter:將當前線程加入到CLH隊列隊尾。
acquireQueued:當前線程會根據公平性原則來進行阻塞等待,直到獲取鎖為止;並且返回當前線程在等待過程中有沒有中斷過。
selfInterrupt:產生一個中斷。
其主要流程如下:
1、首先線程嘗試獲取鎖,如果成功則直接返回,不成功則新建一個Node節點並添加到CLH隊列中。tryAcquire嘗試獲取鎖,addWaiter則新建節點並添加到CLH隊列中。其中tryAcquire,AQS並沒有提供實現,它僅僅只是拋出一個異常,具體的實現需要各個鎖自己實現。
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
addWaiter后面講述。
2、acquireQueued主要功能是根據該節點尋找CLH隊列的頭結點,並且嘗試獲取鎖,判斷是否需要掛起,並且返回掛起標識。如下:
final boolean acquireQueued(final Node node, int arg) { try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } catch (RuntimeException ex) { cancelAcquire(node); throw ex; } }
在acquireQueued()內部仍然調用tryAcquire()來獲取鎖。更多詳情請參考:【Java並發編程實戰】—–“J.U.C”:ReentrantLock之二lock方法分析
selfInterrupt:產生一個中斷。如果在acquireQueued()中當前線程被中斷過,則需要產生一個中斷。
private static void selfInterrupt() { Thread.currentThread().interrupt(); }
AQS鎖釋放
AQS釋放鎖的方法主要有:
release(int arg):以獨占模式釋放對象。
releaseShared(int arg): 以共享模式釋放對象
tryRelease(int arg):試圖設置狀態來反映獨占模式下的一個釋放。
tryReleaseShared(int arg):試圖設置狀態來反映共享模式下的一個釋放。
釋放鎖相對於獲取鎖來說還是比較簡單的,其主要流程如下:
其代碼如下(release()):
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
tryeRelease():嘗試釋放鎖,AQS也同樣沒有提供實現,具體實現方法要其子類自己內部實現,AQS僅僅只是拋出一個異常。
protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); }
unparkSuccessor:用於喚醒節點。更多,請參考:【Java並發編程實戰】—–“J.U.C”:ReentrantLock之三unlock方法分析
參考文獻: