1.Lock 接口
??鎖是用來控制多個(gè)線程訪問共享資源的方式,一般來說, 一個(gè)鎖能夠防止多個(gè)線程同時(shí)訪問共享資源(但是有些鎖可以允許多個(gè)線程并發(fā)的訪問共享資源, 比如讀寫鎖)。在Lock接口出現(xiàn)之前,Java程序是靠synchronized關(guān)鍵字實(shí)現(xiàn)鎖功能的, 而Java SE 5之后,并發(fā)包中新增了Lock接口(以及相關(guān)實(shí)現(xiàn)類)用來實(shí)現(xiàn)鎖功能,它提供了與synchronized關(guān)鍵字類似的同步功能, 只是在使用時(shí)需要顯式地獲取和釋放鎖。雖然它缺少了(通過synchronized塊或者方法所提供的)隱式獲取釋放鎖的便捷性,但是卻擁有了鎖獲取與釋放的可操作性、 可中斷的獲取鎖以及超時(shí)獲取鎖等多種synchronized關(guān)鍵字所不具備的同步特性。
??使用synchronized關(guān)鍵字將會(huì)隱式地獲取鎖,但是 它將鎖的獲取和釋放固化了,也就是先獲取再釋放。當(dāng)然,這種方式簡化了同步的管理,可是擴(kuò)展性沒有顯示的鎖獲取和釋放來的好。
??不要將獲取鎖的過程寫在try塊中, 因?yàn)槿绻讷@取鎖(自定義鎖的實(shí)現(xiàn))時(shí)發(fā)生了異常, 異常拋出的同時(shí), 也會(huì)導(dǎo)致鎖無故釋放。
??Lock 接口提供的 synchronized 關(guān)鍵字所不具備的主要特性如下表所示。

??Lock 是一個(gè)接口,它定義了鎖獲取和釋放的基本操作,Lock的API如下表:

??Lock接口的實(shí)現(xiàn)基本都是能過聚合了一個(gè)同步器的子類完成線程訪問控制的。
2.隊(duì)列同步器
??隊(duì)列同步器AbstractQueuedSynchronizer (以下簡稱同步器), 是用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架, 它使用了一個(gè)int成員變量表示同步狀態(tài), 通過內(nèi)置的FIFO隊(duì)列來完成資源獲取線程的排隊(duì)工作, 并發(fā)包的作者(Doug Lea )期望它能夠成為實(shí)現(xiàn)大部分同步需求 的基礎(chǔ)。
??同步器的主要使用方式是繼承, 子類通過繼承同步器并實(shí)現(xiàn)它的抽象方法來管理同步狀態(tài), 在抽象方法的實(shí)現(xiàn)過程中免不了要對同步狀態(tài)進(jìn)行更改, 這時(shí)就需要使用同步器提供 的3個(gè) 方法(getState()、setState(int newState)和compareAndSetState(int expect, int update)) 來進(jìn)行操作,因?yàn)樗鼈兡軌虮WC狀態(tài)的改變是安全的。 子類推薦被定義為自定義同步組件 的靜態(tài)內(nèi)部類, 同步器自身沒有實(shí)現(xiàn)任何同步接口, 它僅僅是定義了若干同步狀態(tài)獲取和釋放的方法來供自定義同步組件使用, 同步器既可以支持獨(dú)占式地獲取同步狀態(tài), 也可以支持共享式地獲取同步狀態(tài), 這樣就可以方便實(shí)現(xiàn)不同類型的同步組件(ReentrantLock、 ReentrantReadWriteLock和CountDownLatch等) 。
??同步器是實(shí)現(xiàn)鎖(也可以是任意同步組件) 的關(guān)鍵, 在鎖的實(shí)現(xiàn)中聚合同步器, 利用同步器實(shí)現(xiàn)鎖的語義。 可以這樣理解二者之間的關(guān)系:鎖是面向使用者的, 它定義了使用者與 鎖交互的接口(比如可以允許兩個(gè)線程并行訪問), 隱藏了實(shí)現(xiàn)細(xì)節(jié);同步器面向的是鎖的 實(shí)現(xiàn)者, 它簡化了鎖的實(shí)現(xiàn)方式, 屏蔽了同步狀態(tài)管理、 線程的排隊(duì)、等待與喚醒等底層操作。 鎖和同步器很好地隔離了使用者和實(shí)現(xiàn)者所需關(guān)注的領(lǐng)域。
2.1 隊(duì)列同步器的接口與示例
??同步器的設(shè)計(jì)是基于模板方法模式的,使用者需要繼承同步器并重寫指定的方法,隨后將同步器組合在自定義同步組件的實(shí)現(xiàn)中,并調(diào)用同步器提供的模板方法,而這些模板方法將會(huì)調(diào)用使用者重寫的方法。
??重寫同步器指定的方法時(shí),需要使用同步器提供的如下3個(gè)方法來訪問或修改同步狀態(tài)。
??- getState(); 獲取當(dāng)前同步狀態(tài)。
??- setState(int newState):設(shè)置當(dāng)前同步狀態(tài)。
??- compareAndSetState(int expect, int update):使用CAS設(shè)置當(dāng)前狀態(tài),該方法能夠保證狀態(tài)設(shè)置的原子性。


??實(shí)現(xiàn)自定義同步組件時(shí),將會(huì)調(diào)用同步器提供的模板方法,這些(部分)模板方法與描述如下:

??同步器提供的模板方法基本上分為3類:獨(dú)占式獲取與釋放同步狀態(tài)、 共享式獲取與釋放同步狀態(tài)和查詢同步隊(duì)列中的等待線程情況。 自定義同步組件將使用同步器提供的模板方法來實(shí)現(xiàn)自己的同步語義。
??只有掌握了同步器的工作原理才能更加深入地理解并發(fā)包中其他的并發(fā)組件, 所以下面通過一個(gè)獨(dú)占鎖的示例來深入了解一下同步器的工作原理。
??顧名思義, 獨(dú)占鎖就是在同一時(shí)刻只能有一個(gè)線程獲取到鎖, 而其他獲取鎖的線程只能處于同步隊(duì)列中等待, 只有獲取鎖的線程釋放了鎖, 后繼的線程才能夠獲取鎖。
2.2 隊(duì)列同步器的實(shí)現(xiàn)分析
??從實(shí)現(xiàn)角度分析同步器是如何完成線程同步的,主要包括:同步隊(duì)列、獨(dú)占式 同步狀態(tài)獲取與釋放、共享式同步狀態(tài)獲取與釋放以及超時(shí)獲取同步狀態(tài)等同步器的核心數(shù)據(jù)結(jié)構(gòu)與模板方法。
??1.同步隊(duì)列
??同步器依賴內(nèi)部的同步隊(duì)列(一個(gè)FIFO雙向隊(duì)列)來完成同步狀態(tài)的管理,當(dāng)前線程獲取同步狀態(tài)失敗時(shí),同步器會(huì)將當(dāng)前線程以及等待狀態(tài)等信息構(gòu)造成為一個(gè)節(jié)點(diǎn)(Node) 并將其加入同步隊(duì)列,同時(shí)會(huì)阻塞當(dāng)前線程,當(dāng)同步狀態(tài)釋放時(shí),會(huì)把首節(jié)點(diǎn)中的線程喚醒,使其再次嘗試獲取同步狀態(tài)。
??同步隊(duì)列中的節(jié)點(diǎn)(Node)用來保存獲取同步狀態(tài)失敗的線程引用、等待狀態(tài)以及前驅(qū)和后繼節(jié)點(diǎn),節(jié)點(diǎn)的屬性類型與名稱以及描述如下表所示。

??節(jié)點(diǎn)是構(gòu)成同步隊(duì)列(等待隊(duì)列) 的基礎(chǔ),同步器擁有首節(jié)點(diǎn) ( head)和尾節(jié)點(diǎn)(tail),沒有成功獲取同步狀態(tài)的線程將會(huì)成為節(jié)點(diǎn)加入該隊(duì)列的尾部,同步隊(duì)列的基本結(jié)構(gòu)如下圖所示。

??同步器包含了兩個(gè)節(jié)點(diǎn)類型的引用, 一個(gè)指向頭節(jié)點(diǎn), 而另一個(gè)指向尾節(jié)點(diǎn)。 試想一下, 當(dāng)一個(gè)線程成功地獲取了同步狀態(tài)(或者鎖), 其他線程將無法獲取到同步狀態(tài), 轉(zhuǎn)而被構(gòu)造成為節(jié)點(diǎn)并加入到同步隊(duì)列中, 而這個(gè)加入隊(duì)列的過程必須要保證線程安全,因此同步器提供了一個(gè)基于CAS的設(shè)置尾節(jié)點(diǎn)的方法:compareAndSetTail(Node expect, Node update), 它需要傳遞當(dāng)前線程 “認(rèn)為” 的尾節(jié)點(diǎn)和當(dāng)前節(jié)點(diǎn), 只有設(shè)置成功后, 當(dāng)前節(jié)點(diǎn)才正式與之前的尾節(jié)點(diǎn)建立關(guān)聯(lián)。
??同步器將節(jié)點(diǎn)加入到同步隊(duì)列的過程如圖所示。

??同步隊(duì)列遵循FIFO, 首節(jié)點(diǎn)是獲取同步狀態(tài)成功的節(jié)點(diǎn), 首節(jié)點(diǎn)的線程在釋放同步狀態(tài)時(shí), 將會(huì)喚醒后繼節(jié)點(diǎn), 而后繼節(jié)點(diǎn)將會(huì)在獲取同步狀態(tài)成功時(shí)將自己設(shè)置為首節(jié)點(diǎn), 該過程如圖所示。

??設(shè)置首節(jié)點(diǎn)是通過獲取同步狀態(tài)成功的線程來完成的, 由于只有一個(gè)線程能夠成功獲取到同步狀態(tài), 因此設(shè)置頭節(jié)點(diǎn)的方法并不需要使用CAS來保證, 它只需要將首節(jié)點(diǎn)設(shè)置成為原首節(jié)點(diǎn)的后繼節(jié)點(diǎn)并斷開原首節(jié)點(diǎn)的 next引用即可。
&emsp?2.獨(dú)占式同步狀態(tài)獲取與釋放
??通過調(diào)用同步器的 acquire(int arg)方法可以獲取同步狀態(tài), 該方法對中斷不敏感, 也就是由于線程獲取同步狀態(tài)失敗后進(jìn)入同步隊(duì)列中, 后續(xù)對線程進(jìn)行中斷操作時(shí), 線程不會(huì)從 同步隊(duì)列中移出。
??3.共享式同步狀態(tài)獲取與釋放
??共享式獲取與獨(dú)占式獲取最主要的區(qū)別在于同一時(shí)刻能否有多個(gè)線程同時(shí) 獲取到同步狀態(tài)。 以文件的讀寫為例,如果一個(gè)程序在對文件進(jìn)行讀操作, 那么這一時(shí)刻對于該文件的寫操作均被阻塞, 而讀操作能夠同時(shí)進(jìn)行。 寫操作要求對資源的獨(dú)占式訪問, 而讀操作可以是共享式訪問, 兩種不同的訪問模式在 同一時(shí)刻對文件或資源的訪問情況, 如下圖所示。

??通過調(diào)用同步器的acquireShared(int arg)方法可以共享式地獲取同步狀態(tài)。tryAcquireShared(int arg)方法返回值為 int 類型, 當(dāng)返回值大于等于 0 時(shí), 表示能夠獲取到同步狀態(tài)。 因此, 在共享式獲取的自旋過程中, 成功獲取到同步狀態(tài)并退出自旋的條件就是 tryAcquireShared(int arg)方法返回值大于等于 0。
??與獨(dú)占式一樣, 共享式獲取也需要釋放同步狀態(tài), 通過調(diào)用 releaseShared(int arg)方法可以釋放同步狀態(tài)。
4. 獨(dú)占式超時(shí)獲取同步狀態(tài)
??通過調(diào)用同步器的 doAcquireNanos(int arg, long nanosTimeout)方法可以超時(shí)獲取同步狀態(tài), 即在指定的時(shí)間段內(nèi)獲取同步狀態(tài), 如果獲取到同步狀態(tài)則返回 true,否則, 返回 false。該方法提供了傳統(tǒng) Java 同步操作(比如 synchronized 關(guān)鍵字)所不具備的特性。
??在分析該方法的實(shí)現(xiàn)前, 先介紹一下響應(yīng)中斷的同步狀態(tài)獲取過程。在 Java 5 之前, 當(dāng)一個(gè)線程獲取不到鎖而被阻塞在 synchronized 之外時(shí), 對該線程進(jìn)行中斷操作, 此時(shí)該線程的中斷標(biāo)志位會(huì)被修改, 但線程依舊會(huì)阻塞在 synchronized 上, 等待著獲取鎖。在 Java 5 中, 同步器提供了 acquirelnterruptibly(int arg)方法, 這個(gè)方法在等待獲取同步狀態(tài)時(shí), 如果 當(dāng)前線程被中斷, 會(huì)立刻返回, 并拋出 InterruptedException。
??超時(shí)獲取同步狀態(tài)過程可以被視作響應(yīng)中斷獲取同步狀態(tài)過程的 “增強(qiáng)版”, doAcquireNanos(int arg, long nanosTimeout)方法在支持響應(yīng)中斷的基礎(chǔ)上, 增加了超時(shí)獲取 的特性。針對超時(shí)獲取, 主要需要計(jì)算出需要睡眠的時(shí)間間隔 nanosTimeout,為了防止過早通知, nanosTimeout 計(jì)算公式為: nanosTimeout -= now - lastTime,其中 now 為當(dāng)前喚醒時(shí)間, lastTime 為上次喚醒時(shí)間, 如果 nanosTimeout 大于 0 則表示超時(shí)時(shí)間未到, 需要繼續(xù)睡眠 nanosTimeout 納秒, 反之, 表示已經(jīng)超時(shí)。
3.重入鎖
??重人鎖 ReentrantLock,顧名思義, 就是支持重進(jìn)入的鎖, 它表示該鎖能夠支持一個(gè)線程對資源的重復(fù)加鎖。 除此之外, 該鎖的還支持獲取鎖時(shí)的公平和非公平性選擇。
回憶在同步器一節(jié)中的示例( Mutex), 同時(shí)考慮如下場景: 當(dāng)一個(gè)線程調(diào)用 Mutex 的lock()方法獲取鎖之后, 如果再次調(diào)用 lock()方法, 則該線程將會(huì)被自己所阻塞, 原因是 Mutex 在實(shí)現(xiàn)町rAcquire(int acquires)方法時(shí)沒有考慮占有鎖的線程再次獲取鎖的場景, 而在調(diào)用 tryAcquire(int acquires)方法時(shí)返回了 false, 導(dǎo)致該線程被阻塞。簡單地說, Mutex 是一個(gè)不支持重進(jìn)入的鎖。 而 synchronized 關(guān)鍵字隱式的支持重進(jìn)入, 比如一個(gè) synchronized 修飾的遞歸方法, 在方法執(zhí)行時(shí), 執(zhí)行線程在獲取了鎖之后仍能連續(xù)多次地獲得該鎖, 而不像Mutex 由于獲取了鎖, 而在下一次獲取鎖時(shí)出現(xiàn)阻塞自己的情況。
??ReentrantLock 雖然沒能像 synchronized 關(guān)鍵字一樣支持隱式的重進(jìn)入, 但是在調(diào)用lock()方法時(shí), 已經(jīng)獲取到鎖的線程, 能夠再次調(diào)用 lock()方法獲取鎖而不被阻塞。
??這里提到一個(gè)鎖獲取的公平性問題 如果在絕對時(shí)間上, 先對鎖進(jìn)行獲取的請求一定先被滿足, 那么這個(gè)鎖是公平的, 反之, 是不公平的。 公平的獲取鎖, 也就是等待時(shí)間最長的線程最優(yōu)先獲取鎖, 也可以說鎖獲取是順序的。 ReentrantLock 提供了一個(gè)構(gòu)造函數(shù), 能夠控制鎖是否是公平的。
??事實(shí)上, 公平的鎖機(jī)制往往沒有非公平的效率高, 但是, 并不是任何場景都是以TPS作
為唯一的指標(biāo), 公平鎖能夠減少 ‘饑餓’ 發(fā)生的概率, 等待越久的請求越是能夠得到優(yōu)先滿足。
1. 實(shí)現(xiàn)重進(jìn)入
??重進(jìn)入是指任意線程在獲取到鎖之后能夠再次獲取該鎖而不會(huì)被鎖所阻塞, 該特性的實(shí)現(xiàn)需要解決以下兩個(gè)問題。
??1 )錢程再次獲取鎖。 鎖需要去識別獲取鎖的線程是否為當(dāng)前占據(jù)鎖的線程, 如果是,則再次成功獲取。
??2 )鎖的最終釋煎。 線程重復(fù)n次獲取了鎖, 隨后在第n次釋放該鎖后, 其他線程能夠獲取到該鎖。 鎖的最終釋放要求鎖對于獲取進(jìn)行計(jì)數(shù)自增, 計(jì)數(shù)表示當(dāng)前鎖被重復(fù)獲取的次數(shù), 而鎖被釋放時(shí), 計(jì)數(shù)自減, 當(dāng)計(jì)數(shù)等于0時(shí)表示鎖已經(jīng)成功釋放。
??ReentrantLock 是通過組合自定義同步器來實(shí)現(xiàn)鎖的獲取與釋放, 以非公平性(默認(rèn)的) 實(shí)現(xiàn)。
2.公平與非公平獲取鎖的區(qū)別
??公平鎖是按FIFO的原則。而非公平鎖不按照這個(gè)原則。非公平鎖的效率要高,因?yàn)樗恍枰瞿敲炊嗌舷挛那袚Q。
4.讀寫鎖
??只需要在讀操作時(shí)獲取讀鎖, 寫操作時(shí)獲取寫鎖即可。 當(dāng)寫鎖被獲取到時(shí), 后續(xù)(非當(dāng)前寫操作線程)的讀寫操作都會(huì)被阻塞, 寫鎖釋放之后, 所有操作繼續(xù)執(zhí)行, 編程方式相對于使用等待通知機(jī)制的實(shí)現(xiàn)方式而言, 變得簡單明了。
??一般情況下, 讀寫鎖的性能都會(huì)比排它鎖好, 因?yàn)榇蠖鄶?shù)場景讀是多于寫的。 在讀多于寫的情況下, 讀寫鎖能夠提供比排它鎖更好的并發(fā)性和吞吐量。Java并發(fā)包提供讀寫鎖的實(shí)現(xiàn)是 ReentrantReadWriteLock。特性如下:

4.1 讀寫鎖的接口
??ReadWriteLock僅定義了獲取讀鎖和寫鎖的兩個(gè)方法, 即readLock()方法和writeLock()方法,而其實(shí)現(xiàn)一- ReentrantReadWriteLock, 除了接口方法之外, 還提供了一些便于外界監(jiān)方法, 而其實(shí)現(xiàn)
控其內(nèi)部工作狀態(tài)的方法。如下圖:

LockSupport 工具
??LockSupport 定義了一組以park開頭的方法用來阻塞當(dāng)前線程,以及unpark(Thread thread)方法來喚醒一個(gè)被阻塞的線程。

6 Condition 接口
??任意一個(gè) Java 對象, 都擁有一組監(jiān)視器方法(定義在 java.lang.Object 上), 主要包括 wait()、 wait(long timeout)、 notify()以及 notifyAll()方法, 這些方法與 synchronized 同步關(guān)鍵字配合, 可以實(shí)現(xiàn)等待/通知模式。 Condition 接口也提供了類似 Object 的監(jiān)視器方法, 與Lock 配合可以實(shí)現(xiàn)等待/通知模式 但是這兩者在使用方式以及功能特性上還是有差別的。
通過對比 Object 的監(jiān)視器方法和 Condition 接口, 可以更詳細(xì)地了解 Condition 的特性,對比項(xiàng)與結(jié)果如表所示。

6.1 Condition 接口
??Condition 定義了等待/通知兩種類型的方法, 當(dāng)前線程調(diào)用這些方法時(shí), 需要提前獲取到 Condition 對象關(guān)聯(lián)的鎖。 Condition 對象是由 Lock 對象(調(diào)用 Lock 對象的 newCondition() 方法)創(chuàng)建出來的, 換句話說, Condition 是依賴 Lock 對象的。
??Condition 的使用方式比較簡單, 需要注意在調(diào)用方法前獲取鎖。
??一般都會(huì)將 Condition 對象作為成員變量。 當(dāng)調(diào)用await()方法后, 當(dāng)前線程會(huì)釋放鎖并在此等待, 而其他線程調(diào)用 Condition 對象的 signal()方法, 通知當(dāng)前線程后,當(dāng)前線程才從 await()方法返回, 并且在返回前已經(jīng)獲取了鎖。
??Condition定義的(部分)方法以及描述如下圖所示。


??獲取一個(gè) Condition 必須通過 Lock 的 newCondition() 方法。
6.2 Condition 的實(shí)現(xiàn)分析
??Condition Object是同步器AbstractQueuedSynchronizer的內(nèi)部類, 因?yàn)镃ondit_ion的操作需要獲取相關(guān)聯(lián)的鎖, 所以作為同步器的內(nèi)部類也較為合理。 每個(gè)Condition對象都包含著 一個(gè)隊(duì)列(以下稱為 等待隊(duì)列), 該隊(duì)列是Condition對象實(shí)現(xiàn)等待/通知功能的關(guān)鍵。
??下面將分析Condition的實(shí)現(xiàn), 主要包括: 等待隊(duì)列、 等待和通知, 下面提到的Condition如果不加說明均指的是ConditionObject。
??1.等待隊(duì)列
??等待隊(duì)列是一個(gè)FIFO的隊(duì)列,在隊(duì)列中的每個(gè)節(jié)點(diǎn)都包含了一個(gè)線程引用,該線程就是在Condition對象上等待的線程,如果一個(gè)線程調(diào)用了Condition.await()方法 ,那么該線 程將會(huì)釋放鎖、 構(gòu)造成節(jié)點(diǎn)加入等待隊(duì)列 并進(jìn)入等待狀態(tài)。 事實(shí)上, 節(jié)點(diǎn)的定義復(fù)用了同
步器中節(jié)點(diǎn)的定義, 也就是說, 同步隊(duì)列和 等待隊(duì)列中節(jié)點(diǎn)類型都是同步器的靜態(tài)內(nèi)部類AbstractQueuedS ynchronizer.Node。
??一個(gè)Condition 包含 一個(gè)等待隊(duì)列, Condition擁有首節(jié)點(diǎn)( firstWaiter) 和尾節(jié)點(diǎn)( last Waiter)。 當(dāng)前線程調(diào)用 Condition.await()方法, 將會(huì)以當(dāng)前線程構(gòu)造節(jié)點(diǎn), 并將節(jié)點(diǎn)從尾部加入等待隊(duì)列。
??2.等待
??調(diào)用 Condition 的 await()方法(或者以 await 開頭的方法), 會(huì)使當(dāng)前線程進(jìn)入等待隊(duì)列并釋放鎖, 同時(shí)線程狀態(tài)變?yōu)榈却隣顟B(tài)。 當(dāng)從 await()方法返回時(shí), 當(dāng)前線程一定獲取了Condition 相關(guān)聯(lián)的鎖。
??如果從隊(duì)列(同步隊(duì)列和等待隊(duì)列) 的角度看 await()方法, 當(dāng)調(diào)用await()方法時(shí), 相當(dāng)于同步隊(duì)列的首節(jié)點(diǎn)(獲取了鎖的節(jié)點(diǎn))移動(dòng)到 Condition 的等待隊(duì)列中。
??3. 通知
??調(diào)用Condition 的 signal()方法, 將會(huì)喚醒在等待隊(duì)列中等待時(shí)間最長的節(jié)點(diǎn)(首節(jié)點(diǎn)),在喚醒節(jié)點(diǎn)之前,會(huì)將節(jié)點(diǎn)移到同步隊(duì)列中。
??調(diào)用該方法的前置條件是當(dāng)前線程必須獲取了鎖, 可以看到 signal()方法進(jìn)行了 isHeldExclusively()檢查, 也就是當(dāng)前線程必須是獲取了鎖的線程。 接著獲取等待隊(duì)列的首節(jié)點(diǎn),將其移動(dòng)到同步隊(duì)列并使用 LockSupport 喚醒節(jié)點(diǎn)中的線程。
??通過調(diào)用同步器的 enq (Node node)方法, 等待隊(duì)列中的頭節(jié)點(diǎn)線程安全地移動(dòng)到同步隊(duì) 列。 當(dāng)節(jié)點(diǎn)移動(dòng)到同步隊(duì)列后, 當(dāng)前線程再使用 LockSupport 喚醒該節(jié)點(diǎn)的線程。
??被喚醒后的線程, 將從await()方法中的while循環(huán)中退出( isOnSyncQueue (Node node) 方法返回true,節(jié)點(diǎn)已經(jīng)在同步隊(duì)列中), 進(jìn)而調(diào)用同步器的acquir eQueued()方法加入到獲取同步狀態(tài)的競爭中。
??成功獲取同步狀態(tài)(或者說鎖)之后, 被喚醒的線程將從先前調(diào)用的await()方法返回, 此時(shí)該線程已經(jīng)成功 地獲取了鎖。
??Condition的signa!All()方法, 相當(dāng)于對等待隊(duì)列中的每個(gè)節(jié)點(diǎn)均執(zhí)行一次signal()方法,效果就是將等待隊(duì)列中所有節(jié)點(diǎn)全部移動(dòng)到同步隊(duì)列中, 并喚醒 每個(gè)節(jié)點(diǎn)的線程。