并發鎖核心類AQS學習筆記(超詳細)


一、概念

AQS 是 AbstractQueuedSynchronizer 的簡稱,AQS 是一個抽象的隊列式同步器框架,提供了阻塞鎖和 FIFO 隊列實現同步操作。JUC 包中的同步類基本都是基于 AQS 同步器來實現的,如 ReentrantLock,Semaphore 等。

二、原理

1、AQS 工作機制:(三點)

1.如果被請求的共享資源空閑,則將當前請求資源的線程設置為有效的工作線程,并且將共享資源設置為鎖定狀態。

2.如果被請求的共享資源被占用,則將獲取不到鎖的線程加入到隊列中。等到占有線程釋放鎖后喚醒隊列中的任務爭搶鎖,這個隊列為 CLH 隊列。

3.使用state成員變量表示當前的同步狀態,提供 getState,setState,compareAndSetState 進行操作。

2、CLH 隊列:

虛擬的雙向隊列,底層是雙向鏈表,包括head節點和tail結點,僅存在結點之間的關聯關系。AQS將每條請求共享資源的線程封裝成一個CLH鎖隊列的一個結點(Node)來實現鎖的分配。

3、AQS 對資源的共享方式

AQS定義兩種資源共享方式

1.獨占 ( Exclusive ):只有一個線程能執行,如 ReentrantLock。又可分為公平鎖和非公平鎖:

公平鎖:按照線程在隊列中的排隊順序,先到者先拿到鎖

非公平鎖:當線程要獲取鎖時,無視隊列順序直接去搶鎖,誰搶到就是誰的,所以非公平鎖效率較高

2.共享 ( Share ):多個線程可同時執行,如Semaphore、CountDownLatch。

4、AQS 的設計模式

AQS 同步器的設計是基于模板方法模式。使用者繼承AbstractQueuedSynchronizer并重寫指定的方法。實現對于共享資源state的獲取和釋放。

將AQS組合在自定義同步組件的實現中,并調用其模板方法,而這些模板方法會調用使用者重寫的方法。 AQS類中的其他方法都是final ,所以無法被其他類使用,只有這幾個方法可以被其他類使用,自定義同步器時需要重寫下面幾個AQS提供的模板方法:

isHeldExclusively()//該線程是否正在獨占資源。只有用到condition才需要去實現它。

tryAcquire(int)//獨占方式。嘗試獲取資源,成功則返回true,失敗則返回false。

tryRelease(int)//獨占方式。嘗試釋放資源,成功則返回true,失敗則返回false。

tryAcquireShared(int)//共享方式。嘗試獲取資源。負數表示失敗;0表示成功,但沒有剩余可用資源;正數表示成功,且有剩余資源。

tryReleaseShared(int)//共享方式。嘗試釋放資源,成功則返回true,失敗則返回false。

以 ReentrantLock為 例,state初始化為0,表示未鎖定狀態。A線程lock()時,會調用tryAcquire()獨占該鎖并將state+1。此后,其他線程在tryAcquire()時就會失敗,直到A線程unlock()到state=0(即釋放鎖)為止,其它線程才有機會獲取該鎖。當然,釋放鎖之前,A線程自己是可以重復獲取此鎖的(state會累加),這就是可重入的概念。但要注意,獲取多少次就要釋放多少次,這樣才能保證state是能回到零態的。

三、空間結構

AbstractQueuedSynchronizer繼承自AbstractOwnableSynchronizer抽象類,并且實現了Serializable接口,可以進行序列化。

AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable

隊列中Node的頭結點

private transient volatile Node head;? ?

隊列中Node的尾結點

private transient volatile Node tail;?

表示同步狀態的成員變量,使用volatile修飾保證線程可見性

private volatile int state;

返回同步狀態的當前值

protected final int getState() {

return state;

}

設置同步狀態的值

protected final void setState(int newState) {

state = newState;

}

原子地(CAS操作)將同步狀態值設置為給定值update如果當前同步狀態的值等于expect(期望值)

protected final boolean compareAndSetState(int expect, int update) {

return unsafe.compareAndSwapInt(this, stateOffset, expect, update);

}

自旋時間

static final long spinForTimeoutThreshold = 1000L;

Unsafe類實例

private static final Unsafe unsafe = Unsafe.getUnsafe();

state內存偏移地址

private static final long stateOffset;

head內存偏移地址

private static final long headOffset;

tail內存偏移地址

private static final long tailOffset;

節點狀態內存偏移地址

private static final long waitStatusOffset;

next內存偏移地址

private static final long nextOffset;

靜態初始化塊,用于加載內存偏移地址。

static {

try {

stateOffset = unsafe.objectFieldOffset

(AbstractQueuedSynchronizer.class.getDeclaredField("state"));

headOffset = unsafe.objectFieldOffset

(AbstractQueuedSynchronizer.class.getDeclaredField("head"));

tailOffset = unsafe.objectFieldOffset

(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));

waitStatusOffset = unsafe.objectFieldOffset

(Node.class.getDeclaredField("waitStatus"));

nextOffset = unsafe.objectFieldOffset

(Node.class.getDeclaredField("next"));

} catch (Exception ex) { throw new Error(ex); }

}

類構造方法為從抽象構造方法,供子類調用。

protected AbstractQueuedSynchronizer() { }? ?

四、常用方法

acquire

該方法以獨占模式獲取資源,先嘗試獲取鎖,如果獲取失敗則調用addWaiter將該線程加入隊列中。

源碼如下:

public final void acquire(int arg) {

if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

selfInterrupt();

}

由上述源碼可以知道,當一個線程調用acquire時,調用方法流程如下

1.首先調用tryAcquire方法,調用此方法的線程會試圖在獨占模式下獲取對象狀態。此方法應該查詢是否允許它在獨占模式下獲取對象狀態,如果允許,則獲取它。在AbstractQueuedSynchronizer源碼中默認會拋出一個異常,即需要子類去重寫此方法完成自己的邏輯。之后會進行分析。

2.若tryAcquire失敗,則調用addWaiter方法,addWaiter方法完成的功能是將調用此方法的線程封裝成為一個結點并放入Sync queue。

3.調用acquireQueued方法,此方法完成的功能是Sync queue中的結點不斷嘗試獲取資源,若成功,則返回true,否則,返回false。

4.由于tryAcquire默認實現是拋出異常,所以此時,不進行分析,之后會結合一個例子進行分析。

addWaiter

使用快速添加的方式往sync queue尾部添加結點,如果sync queue隊列還沒有初始化,則會使用enq插入隊列中。

// 添加等待者

private Node addWaiter(Node mode) {

// 新生成一個結點,默認為獨占模式

Node node = new Node(Thread.currentThread(), mode);

// Try the fast path of enq; backup to full enq on failure

// 保存尾結點

Node pred = tail;

if (pred != null) { // 尾結點不為空,即已經被初始化

// 將node結點的prev域連接到尾結點

node.prev = pred;

if (compareAndSetTail(pred, node)) { // 比較pred是否為尾結點,是則將尾結點設置為node

// 設置尾結點的next域為node

pred.next = node;

return node; // 返回新生成的結點

}

}

enq(node); // 尾結點為空(即還沒有被初始化過),或者是compareAndSetTail操作失敗,則入隊列

return node;

}

enq

使用無限循環來確保節點的成功插入。

private Node enq(final Node node) {

for (;;) { // 無限循環,確保結點能夠成功入隊列

// 保存尾結點

Node t = tail;

if (t == null) { // 尾結點為空,即還沒被初始化

if (compareAndSetHead(new Node())) // 頭結點為空,并設置頭結點為新生成的結點

tail = head; // 頭結點與尾結點都指向同一個新生結點

} else { // 尾結點不為空,即已經被初始化過

// 將node結點的prev域連接到尾結點

node.prev = t;

if (compareAndSetTail(t, node)) { // 比較結點t是否為尾結點,若是則將尾結點設置為node

// 設置尾結點的next域為node

t.next = node;

return t; // 返回尾結點

}

}

}

}

acquireQueue

首先獲取當前節點的前驅節點,如果前驅節點是頭結點并且能夠獲取(資源),代表該當前節點能夠占有鎖,設置頭結點為當前節點,返回。否則,調用shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法

// sync隊列中的結點在獨占且忽略中斷的模式下獲取(資源)

final boolean acquireQueued(final Node node, int arg) {

// 標志

boolean failed = true;

try {

// 中斷標志

boolean interrupted = false;

for (;;) { // 無限循環

// 獲取node節點的前驅結點

final Node p = node.predecessor();

if (p == head && tryAcquire(arg)) { // 前驅為頭結點并且成功獲得鎖

setHead(node); // 設置頭結點

p.next = null; // help GC

failed = false; // 設置標志

return interrupted;

}

if (shouldParkAfterFailedAcquire(p, node) &&

parkAndCheckInterrupt())

interrupted = true;

}

} finally {

if (failed)

cancelAcquire(node);

}

}

shouldParkAfterFailedAcquire和方法,首先,我們看

shouldParkAfterFailedAcquire

只有當該節點的前驅結點的狀態為SIGNAL時,才可以對該結點所封裝的線程進行park操作。否則,將不能進行park操作。

// 當獲取(資源)失敗后,檢查并且更新結點狀態

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

// 獲取前驅結點的狀態

int ws = pred.waitStatus;

if (ws == Node.SIGNAL) // 狀態為SIGNAL,為-1

// 可以進行park操作

return true;

if (ws > 0) { // 表示狀態為CANCELLED,為1

do {

node.prev = pred = pred.prev;

} while (pred.waitStatus > 0); // 找到pred結點前面最近的一個狀態不為CANCELLED的結點

// 賦值pred結點的next域

pred.next = node;

} else { // 為PROPAGATE -3 或者是0 表示無狀態,(為CONDITION -2時,表示此節點在condition queue中)

// 比較并設置前驅結點的狀態為SIGNAL

compareAndSetWaitStatus(pred, ws, Node.SIGNAL);

}

// 不能進行park操作

return false;

}

parkAndCheckInterrupt

首先執行park操作,即禁用當前線程,然后返回該線程是否已經被中斷

// 進行park操作并且返回該線程是否被中斷

private final boolean parkAndCheckInterrupt() {

// 在許可可用之前禁用當前線程,并且設置了blocker

LockSupport.park(this);

return Thread.interrupted(); // 當前線程是否已被中斷,并清除中斷標記位

}

cancelAcquire

該方法完成的功能就是取消當前線程對資源的獲取,即設置該節點的狀態為CANCELLED

// 取消繼續獲取(資源)

private void cancelAcquire(Node node) {

// Ignore if node doesn't exist

// node為空,返回

if (node == null)

return;

// 設置node結點的thread為空

node.thread = null;

// Skip cancelled predecessors

// 保存node的前驅結點

Node pred = node.prev;

while (pred.waitStatus > 0) // 找到node前驅結點中第一個狀態小于0的結點,即不為CANCELLED狀態的結點

node.prev = pred = pred.prev;

// 獲取pred結點的下一個結點

Node predNext = pred.next;

// 設置node結點的狀態為CANCELLED

node.waitStatus = Node.CANCELLED;

// If we are the tail, remove ourselves.

if (node == tail && compareAndSetTail(node, pred)) { // node結點為尾結點,則設置尾結點為pred結點

// 比較并設置pred結點的next節點為null

compareAndSetNext(pred, predNext, null);

} else { // node結點不為尾結點,或者比較設置不成功

int ws;

if (pred != head &&

((ws = pred.waitStatus) == Node.SIGNAL ||

(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&

pred.thread != null) { // (pred結點不為頭結點,并且pred結點的狀態為SIGNAL)或者

// pred結點狀態小于等于0,并且比較并設置等待狀態為SIGNAL成功,并且pred結點所封裝的線程不為空

// 保存結點的后繼

Node next = node.next;

if (next != null && next.waitStatus <= 0) // 后繼不為空并且后繼的狀態小于等于0

compareAndSetNext(pred, predNext, next); // 比較并設置pred.next = next;

} else {

unparkSuccessor(node); // 釋放node的前一個結點

}

node.next = node; // help GC

}

}

unparkSuccessor

該方法的作用就是為了釋放node節點的后繼節點。

// 釋放后繼結點

private void unparkSuccessor(Node node) {

// 獲取node結點的等待狀態

int ws = node.waitStatus;

if (ws < 0) // 狀態值小于0,為SIGNAL -1 或 CONDITION -2 或 PROPAGATE -3

// 比較并且設置結點等待狀態,設置為0

compareAndSetWaitStatus(node, ws, 0);

// 獲取node節點的下一個結點

Node s = node.next;

if (s == null || s.waitStatus > 0) { // 下一個結點為空或者下一個節點的等待狀態大于0,即為CANCELLED

// s賦值為空

s = null;

// 從尾結點開始從后往前開始遍歷

for (Node t = tail; t != null && t != node; t = t.prev)

if (t.waitStatus <= 0) // 找到等待狀態小于等于0的結點,找到最前的狀態小于等于0的結點

// 保存結點

s = t;

}

if (s != null) // 該結點不為為空,釋放許可

LockSupport.unpark(s.thread);

}

對于cancelAcquire與unparkSuccessor方法,如下示意圖可以清晰的表示:

其中node為參數,在執行完cancelAcquire方法后的效果就是unpark了s結點所包含的t4線程。

現在,再來看acquireQueued方法的整個的邏輯。邏輯如下:

判斷結點的前驅是否為head并且是否成功獲取(資源)。

若步驟1均滿足,則設置結點為head,之后會判斷是否finally模塊,然后返回。

若步驟2不滿足,則判斷是否需要park當前線程,是否需要park當前線程的邏輯是判斷結點的前驅結點的狀態是否為SIGNAL,若是,則park當前結點,否則,不進行park操作。

若park了當前線程,之后某個線程對本線程unpark后,并且本線程也獲得機會運行。那么,將會繼續進行步驟①的判斷。

release

以獨占模式釋放對象,其中 tryRelease 的默認實現是拋出異常,需要具體的子類實現,如果 tryRelease 成功,那么如果頭結點不為空并且頭結點的狀態不為 0,則釋放頭結點的后繼結點。

public final boolean release(int arg) {

if (tryRelease(arg)) { // 釋放成功

// 保存頭結點

Node h = head;

if (h != null && h.waitStatus != 0) // 頭結點不為空并且頭結點狀態不為0

unparkSuccessor(h); //釋放頭結點的后繼結點

return true;

}

return false;

}

五、內部類

Node類

每個線程被阻塞的線程都會被封裝成一個Node結點,放入隊列。每個節點包含了一個Thread類型的引用,并且每個節點都存在一個狀態,具體狀態如下。

1.CANCELLED,值為1,表示當前的線程被取消。

2.SIGNAL,值為-1,表示當前節點的后繼節點包含的線程需要運行,需要進行unpark操作。

3.CONDITION,值為-2,表示當前節點在等待condition,也就是在condition queue中。

4.PROPAGATE,值為-3,表示當前場景下后續的acquireShared能夠得以執行。

5.值為0,表示當前節點在sync queue中,等待著獲取鎖。

static final class Node {

// 模式,分為共享與獨占

// 共享模式

static final Node SHARED = new Node();

// 獨占模式

static final Node EXCLUSIVE = null;

// 結點狀態

// CANCELLED,值為1,表示當前的線程被取消

// SIGNAL,值為-1,表示當前節點的后繼節點包含的線程需要運行,也就是unpark

// CONDITION,值為-2,表示當前節點在等待condition,也就是在condition隊列中

// PROPAGATE,值為-3,表示當前場景下后續的acquireShared能夠得以執行

// 值為0,表示當前節點在sync隊列中,等待著獲取鎖

static final int CANCELLED =? 1;

static final int SIGNAL? ? = -1;

static final int CONDITION = -2;

static final int PROPAGATE = -3;

// 結點狀態

volatile int waitStatus;

// 前驅結點

volatile Node prev;

// 后繼結點

volatile Node next;

// 結點所對應的線程

volatile Thread thread;

// 下一個等待者

Node nextWaiter;

// 結點是否在共享模式下等待

final boolean isShared() {

return nextWaiter == SHARED;

}

// 獲取前驅結點,若前驅結點為空,拋出異常

final Node predecessor() throws NullPointerException {

// 保存前驅結點

Node p = prev;

if (p == null) // 前驅結點為空,拋出異常

throw new NullPointerException();

else // 前驅結點不為空,返回

return p;

}

// 無參構造方法

Node() {? ? // Used to establish initial head or SHARED marker

}

// 構造方法

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;

}

}

ConditionObject類

// 內部類

public class ConditionObject implements Condition, java.io.Serializable {

// 版本號

private static final long serialVersionUID = 1173984872572414699L;

// condition隊列的頭結點

private transient Node firstWaiter;

// condition隊列的尾結點

private transient Node lastWaiter;

// 構造方法

public ConditionObject() { }

// 添加新的waiter到wait隊列

private Node addConditionWaiter() {

// 保存尾結點

Node t = lastWaiter;

// 尾結點不為空,并且尾結點的狀態不為CONDITION

if (t != null && t.waitStatus != Node.CONDITION) {

// 清除狀態為CONDITION的結點

unlinkCancelledWaiters();

// 將最后一個結點重新賦值給t

t = lastWaiter;

}

// 新建一個結點

Node node = new Node(Thread.currentThread(), Node.CONDITION);

if (t == null) // 尾結點為空

// 設置condition隊列的頭結點

firstWaiter = node;

else // 尾結點不為空

// 設置為節點的nextWaiter域為node結點

t.nextWaiter = node;

// 更新condition隊列的尾結點

lastWaiter = node;

return node;

}

private void doSignal(Node first) {

// 循環

do {

if ( (firstWaiter = first.nextWaiter) == null) // 該節點的nextWaiter為空

// 設置尾結點為空

lastWaiter = null;

// 設置first結點的nextWaiter域

first.nextWaiter = null;

} while (!transferForSignal(first) &&

(first = firstWaiter) != null); // 將結點從condition隊列轉移到sync隊列失敗并且condition隊列中的頭結點不為空,一直循環

}

private void doSignalAll(Node first) {

// condition隊列的頭結點尾結點都設置為空

lastWaiter = firstWaiter = null;

// 循環

do {

// 獲取first結點的nextWaiter域結點

Node next = first.nextWaiter;

// 設置first結點的nextWaiter域為空

first.nextWaiter = null;

// 將first結點從condition隊列轉移到sync隊列

transferForSignal(first);

// 重新設置first

first = next;

} while (first != null);

}

// 從condition隊列中清除狀態為CANCEL的結點

private void unlinkCancelledWaiters() {

// 保存condition隊列頭結點

Node t = firstWaiter;

Node trail = null;

while (t != null) { // t不為空

// 下一個結點

Node next = t.nextWaiter;

if (t.waitStatus != Node.CONDITION) { // t結點的狀態不為CONDTION狀態

// 設置t節點的額nextWaiter域為空

t.nextWaiter = null;

if (trail == null) // trail為空

// 重新設置condition隊列的頭結點

firstWaiter = next;

else // trail不為空

// 設置trail結點的nextWaiter域為next結點

trail.nextWaiter = next;

if (next == null) // next結點為空

// 設置condition隊列的尾結點

lastWaiter = trail;

}

else // t結點的狀態為CONDTION狀態

// 設置trail結點

trail = t;

// 設置t結點

t = next;

}

}

// 喚醒一個等待線程。如果所有的線程都在等待此條件,則選擇其中的一個喚醒。在從 await 返回之前,該線程必須重新獲取鎖。

public final void signal() {

if (!isHeldExclusively()) // 不被當前線程獨占,拋出異常

throw new IllegalMonitorStateException();

// 保存condition隊列頭結點

Node first = firstWaiter;

if (first != null) // 頭結點不為空

// 喚醒一個等待線程

doSignal(first);

}

// 喚醒所有等待線程。如果所有的線程都在等待此條件,則喚醒所有線程。在從 await 返回之前,每個線程都必須重新獲取鎖。

public final void signalAll() {

if (!isHeldExclusively()) // 不被當前線程獨占,拋出異常

throw new IllegalMonitorStateException();

// 保存condition隊列頭結點

Node first = firstWaiter;

if (first != null) // 頭結點不為空

// 喚醒所有等待線程

doSignalAll(first);

}

// 等待,當前線程在接到信號之前一直處于等待狀態,不響應中斷

public final void awaitUninterruptibly() {

// 添加一個結點到等待隊列

Node node = addConditionWaiter();

// 獲取釋放的狀態

int savedState = fullyRelease(node);

boolean interrupted = false;

while (!isOnSyncQueue(node)) { //

// 阻塞當前線程

LockSupport.park(this);

if (Thread.interrupted()) // 當前線程被中斷

// 設置interrupted狀態

interrupted = true;

}

if (acquireQueued(node, savedState) || interrupted)

selfInterrupt();

}

private static final int REINTERRUPT =? 1;

private static final int THROW_IE? ? = -1;

private int checkInterruptWhileWaiting(Node node) {

return Thread.interrupted() ?

(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :

0;

}

private void reportInterruptAfterWait(int interruptMode)

throws InterruptedException {

if (interruptMode == THROW_IE)

throw new InterruptedException();

else if (interruptMode == REINTERRUPT)

selfInterrupt();

}

// 等待,當前線程在接到信號或被中斷之前一直處于等待狀態

public final void await() throws InterruptedException {

if (Thread.interrupted()) // 當前線程被中斷,拋出異常

throw new InterruptedException();

// 在wait隊列上添加一個結點

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);

}

// 等待,當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態

public final long awaitNanos(long nanosTimeout)

throws InterruptedException {

if (Thread.interrupted())

throw new InterruptedException();

Node node = addConditionWaiter();

int savedState = fullyRelease(node);

final long deadline = System.nanoTime() + nanosTimeout;

int interruptMode = 0;

while (!isOnSyncQueue(node)) {

if (nanosTimeout <= 0L) {

transferAfterCancelledWait(node);

break;

}

if (nanosTimeout >= spinForTimeoutThreshold)

LockSupport.parkNanos(this, nanosTimeout);

if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)

break;

nanosTimeout = deadline - System.nanoTime();

}

if (acquireQueued(node, savedState) && interruptMode != THROW_IE)

interruptMode = REINTERRUPT;

if (node.nextWaiter != null)

unlinkCancelledWaiters();

if (interruptMode != 0)

reportInterruptAfterWait(interruptMode);

return deadline - System.nanoTime();

}

// 等待,當前線程在接到信號、被中斷或到達指定最后期限之前一直處于等待狀態

public final boolean awaitUntil(Date deadline)

throws InterruptedException {

long abstime = deadline.getTime();

if (Thread.interrupted())

throw new InterruptedException();

Node node = addConditionWaiter();

int savedState = fullyRelease(node);

boolean timedout = false;

int interruptMode = 0;

while (!isOnSyncQueue(node)) {

if (System.currentTimeMillis() > abstime) {

timedout = transferAfterCancelledWait(node);

break;

}

LockSupport.parkUntil(this, abstime);

if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)

break;

}

if (acquireQueued(node, savedState) && interruptMode != THROW_IE)

interruptMode = REINTERRUPT;

if (node.nextWaiter != null)

unlinkCancelledWaiters();

if (interruptMode != 0)

reportInterruptAfterWait(interruptMode);

return !timedout;

}

// 等待,當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態。此方法在行為上等效于: awaitNanos(unit.toNanos(time)) > 0

public final boolean await(long time, TimeUnit unit)

throws InterruptedException {

long nanosTimeout = unit.toNanos(time);

if (Thread.interrupted())

throw new InterruptedException();

Node node = addConditionWaiter();

int savedState = fullyRelease(node);

final long deadline = System.nanoTime() + nanosTimeout;

boolean timedout = false;

int interruptMode = 0;

while (!isOnSyncQueue(node)) {

if (nanosTimeout <= 0L) {

timedout = transferAfterCancelledWait(node);

break;

}

if (nanosTimeout >= spinForTimeoutThreshold)

LockSupport.parkNanos(this, nanosTimeout);

if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)

break;

nanosTimeout = deadline - System.nanoTime();

}

if (acquireQueued(node, savedState) && interruptMode != THROW_IE)

interruptMode = REINTERRUPT;

if (node.nextWaiter != null)

unlinkCancelledWaiters();

if (interruptMode != 0)

reportInterruptAfterWait(interruptMode);

return !timedout;

}

final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {

return sync == AbstractQueuedSynchronizer.this;

}

//? 查詢是否有正在等待此條件的任何線程

protected final boolean hasWaiters() {

if (!isHeldExclusively())

throw new IllegalMonitorStateException();

for (Node w = firstWaiter; w != null; w = w.nextWaiter) {

if (w.waitStatus == Node.CONDITION)

return true;

}

return false;

}

// 返回正在等待此條件的線程數估計值

protected final int getWaitQueueLength() {

if (!isHeldExclusively())

throw new IllegalMonitorStateException();

int n = 0;

for (Node w = firstWaiter; w != null; w = w.nextWaiter) {

if (w.waitStatus == Node.CONDITION)

++n;

}

return n;

}

// 返回包含那些可能正在等待此條件的線程集合

protected final Collection getWaitingThreads() {

if (!isHeldExclusively())

throw new IllegalMonitorStateException();

ArrayList list = new ArrayList();

for (Node w = firstWaiter; w != null; w = w.nextWaiter) {

if (w.waitStatus == Node.CONDITION) {

Thread t = w.thread;

if (t != null)

list.add(t);

}

}

return list;

}

}

此類實現了Condition接口,Condition接口定義了條件操作規范,具體如下

public interface Condition {

// 等待,當前線程在接到信號或被中斷之前一直處于等待狀態

void await() throws InterruptedException;

// 等待,當前線程在接到信號之前一直處于等待狀態,不響應中斷

void awaitUninterruptibly();

//等待,當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態

long awaitNanos(long nanosTimeout) throws InterruptedException;

// 等待,當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態。此方法在行為上等效于: awaitNanos(unit.toNanos(time)) > 0

boolean await(long time, TimeUnit unit) throws InterruptedException;

// 等待,當前線程在接到信號、被中斷或到達指定最后期限之前一直處于等待狀態

boolean awaitUntil(Date deadline) throws InterruptedException;

// 喚醒一個等待線程。如果所有的線程都在等待此條件,則選擇其中的一個喚醒。在從 await 返回之前,該線程必須重新獲取鎖。

void signal();

// 喚醒所有等待線程。如果所有的線程都在等待此條件,則喚醒所有線程。在從 await 返回之前,每個線程都必須重新獲取鎖。

void signalAll();

}

原文鏈接:https://blog.csdn.net/tc979907461/article/details/105979761

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374