java.util.concurrent.locks.Condition文档说明
【1】Condition接口文檔描述
1.Condition類把Object監(jiān)視器方法(wait,nofify, notifyAll)分解為不同對象,通過與Lock實現(xiàn)類的合并使用,Condition可以產(chǎn)生每個object都有多個等待集的效果。在Lock實現(xiàn)類替代synchronized方法或語句塊的地方,Condition可以替換Object監(jiān)視器方法。
2.Conditions(也稱為條件隊列或條件變量),為一個線程提供了掛起執(zhí)行(等待)的方法,直到另一個線程通知它某些狀態(tài)條件可能為真。
3.因為對共享狀態(tài)信息的訪問發(fā)生在不同線程,該共享信息必須被保護(hù),因此某種形式的鎖與condition條件相關(guān)聯(lián)。等待條件提供的關(guān)鍵屬性是它(條件-condition)可以原子性釋放關(guān)聯(lián)的鎖并掛起當(dāng)前線程,就像Object.wait() 方法那樣。
4.condition-條件實例本質(zhì)上是綁定到鎖Lock上的。要獲取特定Lock實例的條件對象,使用newCondition() 方法;
5.舉個例子(這個例子非常經(jīng)典-類似消息隊列),假設(shè)我們有一個支持put和take 方法的有界緩沖區(qū)。若嘗試對空緩存區(qū)執(zhí)行take操作,則線程阻塞直到緩沖區(qū)有元素;若嘗試對滿緩存區(qū)執(zhí)行put操作,則線程阻塞直到緩存區(qū)有可用空間。 我們想要把 執(zhí)行put方法和task方法阻塞的線程放在單獨(dú)的等待集合中,以便我們可以使用優(yōu)化,當(dāng)緩存區(qū)中元素或空間可用時, 僅通知一個線程。
這可以通過使用兩個 Condition-條件實例來實現(xiàn),如下(這段代碼非常重要):
class BoundedBuffer { // 有界緩沖區(qū) final Lock lock = new ReentrantLock();// 可重入鎖final Condition notFull = lock.newCondition(); // 不為滿的條件final Condition notEmpty = lock.newCondition(); // 不為空的條件final Object[] items = new Object[100];int putptr, takeptr, count;// 插入元素 public void put(Object x) throws InterruptedException {lock.lock();// 獲取鎖 try {while (count == items.length)// 當(dāng)緩沖區(qū)滿,則自旋式阻塞notFull.await();// 等待 items[putptr] = x;// 不滿,則添加元素到緩沖區(qū) if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();// 喚醒在非空條件上阻塞的線程} finally {lock.unlock();// 解鎖}}// 獲取元素 public Object take() throws InterruptedException {lock.lock();// 獲取鎖 try {while (count == 0)notEmpty.await();// 若緩存區(qū)空,則非空條件阻塞 Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();// 喚醒非滿條件return x;} finally {lock.unlock();// 解鎖}}}(java.util.concurrent.ArrayBlockingQueue實現(xiàn)了上述例子,無需自己寫代碼實現(xiàn))
6.Condition實現(xiàn)類可以提供不同于Object監(jiān)視器方法的行為和語義,如保證通知順序,執(zhí)行通知時無需持有鎖。如果一個Condition實現(xiàn)類提供了這些專門語義,則需要記錄這些語義。
7.注意到:
- Condition實例也僅僅是普通對象,所以可以作為 synchronized方法或語句塊的目標(biāo)對象,也可以調(diào)用Condition對象的監(jiān)視器wait() 和 notify方法。獲取Condition實例的監(jiān)視器鎖,或使用監(jiān)視器方法(wait,notify,notifyAll),與獲取condition相關(guān)的Lock鎖或使用其wait或signal方法沒有任何關(guān)系。墻裂建議為了避免混淆,不要在把 Conditoin實例作為 synchronized的目標(biāo)對象,除非在它們自己的實現(xiàn)中。
8.Condition實現(xiàn)類注意事項:
在等待條件時,通常允許發(fā)生虛假喚醒,作為對底層平臺語義的讓步。
這對大多數(shù)應(yīng)用程序來說沒有影響,因為condition-條件應(yīng)該始終在循環(huán)中等待,以測試等待的狀態(tài)謂詞(變量是否為真)。
Conditon實現(xiàn)類可以自由移除虛假喚醒的可能性,但墻裂建議程序員始終假設(shè)它可能發(fā)生,因此始終在循環(huán)中等待;
9.3種形式的條件等待(可中斷,不可中斷,超時)在一些平臺的實現(xiàn)難易程度和性能特征有所不同。特別地,可能很難提供這些特性并維護(hù)特定語義,如順序保證。此外,中斷一個線程的實際掛起的能力在所有平臺并不總是可行的;
10.因此,Condition實現(xiàn)類不需要為以上3種形式的等待精確定義同樣的保證和語義。也不需要支持對線程實際掛起的中斷。
11.一個Condition實現(xiàn)類需要記錄每個wait方法提供的語義和保證,當(dāng)Condition實現(xiàn)類支持線程掛起時的中斷,則它必須遵守本接口定義的中斷語義。
12.中斷通常意味著取消,并且中斷檢測不常發(fā)生,所以Condition實現(xiàn)類傾向于響應(yīng)中斷而不是方法正常返回。即使證明中斷發(fā)生在另一動作解除線程阻塞之后發(fā)生,也是如此。Condition實現(xiàn)類應(yīng)該記錄這些行為。
【2】Condition方法
【2.1】void await() throws InterruptedException
1.該方法導(dǎo)致當(dāng)前線程等待,直到收到信號或被中斷。
2.與此Condition關(guān)聯(lián)的鎖被自動釋放,且當(dāng)前線程無法被線程調(diào)度器調(diào)度(禁用),并處于休眠狀態(tài)直到以下4種情況之一發(fā)生:
- 情況1,其他線程調(diào)用此condition的信號方法(signal),并且當(dāng)前線程恰好被選擇為要被喚醒的線程 ;
- 情況2 ,其他線程調(diào)用此condition的signalAll方法;
- 情況3 , 其他線程中斷了當(dāng)前線程,(當(dāng)Condition實現(xiàn)類支持線程掛起時的中斷);
- 情況4, 發(fā)生虛假喚醒(?);
3.在所有情況下,在await() 方法從當(dāng)前線程返回之前,當(dāng)前線程都必須重新獲取與condition關(guān)聯(lián)的鎖。當(dāng)線程返回時,能夠保證它持有鎖。
4.如果當(dāng)前線程:
在該方法入口設(shè)置了中斷狀態(tài),或等待時被中斷(且condition實現(xiàn)類支持線程掛起時被中斷),
則線程將拋出InterruptedException-中斷異常,且當(dāng)前線程的中斷狀態(tài)被清空。
對于第一種情況,在釋放鎖之前是否進(jìn)行中斷測試沒有規(guī)定。
5.Condition實現(xiàn)類注意事項:
在本方法被調(diào)用時,假設(shè)當(dāng)前線程持有了condition對象關(guān)聯(lián)的鎖。
這取決于condition實現(xiàn)類確定是否是這種情況,如果不是,如何響應(yīng)。通常,會拋出異常(如IllegalMonitorStateException-非法監(jiān)視器狀態(tài)異常),且condition實現(xiàn)類會記錄該事實。
6.在響應(yīng)信號過程中,condition實現(xiàn)類傾向于響應(yīng)中斷而不是方法正常返回。在那種情況下,condition實現(xiàn)類必須保證信號被重定向到其他等待線程(即,sinal發(fā)給其他線程以喚醒),如果有的話 。
7.拋出異常:
InterruptedException-中斷異常,當(dāng)當(dāng)前線程被中斷(當(dāng)condition實現(xiàn)類支持線程掛起時中斷)
【2.2】void awaitUninterruptibly()
1.導(dǎo)致當(dāng)前線程等待,直到被發(fā)出信號。
2.與此contition對象關(guān)聯(lián)的鎖被自動釋放,當(dāng)前線程無法被線程調(diào)度器調(diào)度(禁用), 并休眠直到以下3種情況之一發(fā)生;
- 情況1, 其他線程調(diào)用了該condition對象的 signal() 方法,且當(dāng)前線程被選為要喚醒的線程;
- 情況2,其他線程調(diào)用了 該condition對象的 signalAll() 方法;
- 情況3,發(fā)生 虛假喚醒(?);
3.在所有情況下,在awaitUninterruptibly() 方法從當(dāng)前線程返回之前,當(dāng)前線程都必須重新獲取與condition關(guān)聯(lián)的鎖。當(dāng)線程返回時,能夠保證它持有鎖。
4.若在該方法入口設(shè)置了當(dāng)前線程的中斷狀態(tài),或等待時被中斷(且condition實現(xiàn)類支持線程掛起時被中斷),該線程會繼續(xù)等待直到接收到信號(不會中斷)。當(dāng)線程最終從該方法返回時,它的中斷狀態(tài)仍然被設(shè)置。
5.Condition實現(xiàn)類注意事項:
在本方法被調(diào)用時,假設(shè)當(dāng)前線程持有了condition對象關(guān)聯(lián)的鎖。
這取決于condition實現(xiàn)類確定是否是這種情況,如果不是,如何響應(yīng)。通常,會拋出異常(如IllegalMonitorStateException-非法監(jiān)視器狀態(tài)異常),且condition實現(xiàn)類會記錄該事實。
【2.3】long awaitNanos(long nanosTimeout) throws InterruptedException
1.導(dǎo)致當(dāng)前線程等待直到接收到信號,或被中斷,或經(jīng)過給定的等待時間。
2.與此contition對象關(guān)聯(lián)的鎖被自動釋放,當(dāng)前線程無法被線程調(diào)度器調(diào)度(禁用), 并休眠直到以下5種情況之一發(fā)生;
- 情況1, 其他線程調(diào)用了該condition對象的 signal() 方法,且當(dāng)前線程被選為要喚醒的線程;
- 情況2,其他線程調(diào)用了 該condition對象的 signalAll() 方法;
- 情況3,其他線程中斷了當(dāng)前線程,(當(dāng)Condition實現(xiàn)類支持線程掛起時的中斷);
- 情況4,經(jīng)過給定的等待時間;
- 情況5,虛假喚醒;
3.在所有情況下,在該方法從當(dāng)前線程返回之前,當(dāng)前線程都必須重新獲取與condition關(guān)聯(lián)的鎖。當(dāng)線程返回時,能夠保證它持有鎖。
4.若在該方法入口設(shè)置了當(dāng)前線程的中斷狀態(tài),或等待時被中斷(且condition實現(xiàn)類支持線程掛起時被中斷),則線程將拋出InterruptedException-中斷異常,且當(dāng)前線程的中斷狀態(tài)被清空。
對于第一種情況,在釋放鎖之前是否進(jìn)行中斷測試沒有規(guī)定。
5.該方法根據(jù)給定的超時納秒數(shù)返回剩余等待納秒數(shù)的估計值。若超時,則該值小于或等于0.
該值可以用于確定在等待返回但等待條件不滿足的情況下是否重新等待以及重新等待多長時間。典型用法如下:
boolean aMethod(long timeout, TimeUnit unit) {long nanos = unit.toNanos(timeout);lock.lock();try {while (!conditionBeingWaitedFor()) {if (nanos <= 0L)return false;nanos = theCondition.awaitNanos(nanos);}// ...} finally {lock.unlock();}}設(shè)計說明:該方法需要一個納秒?yún)?shù),以避免報告剩余時間時出現(xiàn)截斷錯誤。這樣的精度丟失將使程序員難以確保系統(tǒng)上的總等待時間不會短于重新等待時的指定值。
6.condition實現(xiàn)類注意事項:
在本方法被調(diào)用時,假設(shè)當(dāng)前線程持有了condition對象關(guān)聯(lián)的鎖。
這取決于condition實現(xiàn)類確定是否是這種情況,如果不是,如何響應(yīng)。通常,會拋出異常(如IllegalMonitorStateException-非法監(jiān)視器狀態(tài)異常),且condition實現(xiàn)類會記錄該事實。
7.在響應(yīng)信號過程中,condition實現(xiàn)類傾向于響應(yīng)中斷而不是方法正常返回或者超過給定等待時間。在任何情況下,condition實現(xiàn)類必須保證信號被重定向到其他等待線程(即,sinal發(fā)給其他線程以喚醒),如果有的話 。
8.參數(shù):
- nanosTimeout, 最大等待時間的納秒數(shù);
9.返回:
- 給定的最大等待時間減去等待花費(fèi)時間的估計值。正數(shù)可以用于該方法的后續(xù)調(diào)用以完成等待所需時間。該值小于或等于0,表明沒有剩余的等待時間了,即無需再等待了。
10.拋出異常
- InterruptedException-中斷異常,如果當(dāng)前線程被中斷(condition實現(xiàn)類支持線程掛起時中斷)
【2.4】boolean await(long time, TimeUnit unit) throws InterruptedException
1.導(dǎo)致當(dāng)前線程等待直到接收到信號,或被中斷,或經(jīng)過給定的等待時間。該方法等價于 awaitNanos(...) 方法,
awaitNanos(unit.toNanos(time)) > 02.參數(shù)
- time, 等待的最長時間;
- unit,time參數(shù)的單位,如時、分、秒
3.返回:
- 若方法返回前可以檢測到等待時間已經(jīng)過去,則返回false;否則返回true;
- 即等待已超時,返回false,否則返回true;
4.拋出異常:
- InterruptedException-中斷異常,如果當(dāng)前線程被中斷(condition實現(xiàn)類支持線程掛起時中斷)
【2.5】boolean awaitUntil(Date deadline) throws InterruptedException
1.導(dǎo)致當(dāng)前線程等待直到收到信號,或中斷,或經(jīng)過了給定的截止日期。
2.與condition關(guān)聯(lián)的鎖會被自動釋放,且當(dāng)前線程會被線程調(diào)度器禁用并休眠,直到以下5種情況之一發(fā)生:
- 情況1,其他線程調(diào)用signal() 信號方法,且當(dāng)前線程被選為要喚醒的線程;
- 情況2,其他線程調(diào)用 signalAll()方法;
- 情況3,其他線程中斷了當(dāng)前線程(condition實現(xiàn)類支持線程掛起時中斷);
- 情況4,經(jīng)過指定的截止日期;
- 情況5,發(fā)生虛假喚醒;
3.在所有情況下,在該方法從當(dāng)前線程返回之前,當(dāng)前線程都必須重新獲取與condition關(guān)聯(lián)的鎖。當(dāng)線程返回時,能夠保證它持有鎖。
4.若在該方法入口設(shè)置了當(dāng)前線程的中斷狀態(tài),或等待時被中斷(且condition實現(xiàn)類支持線程掛起時被中斷),則線程將拋出InterruptedException-中斷異常,且當(dāng)前線程的中斷狀態(tài)被清空。
對于第一種情況,在釋放鎖之前是否進(jìn)行中斷測試沒有規(guī)定。
5.返回值 表明是否經(jīng)過了截止期限,可以如下使用:
boolean aMethod(Date deadline) {boolean stillWaiting = true;lock.lock();try {while (!conditionBeingWaitedFor()) {if (!stillWaiting)return false;stillWaiting = theCondition.awaitUntil(deadline);// 等待,返回是否過了截止期限}// ...} finally {lock.unlock();}}6.實施注意事項
在本方法被調(diào)用時,假設(shè)當(dāng)前線程持有了condition對象關(guān)聯(lián)的鎖。
這取決于condition實現(xiàn)類確定是否是這種情況,如果不是,如何響應(yīng)。通常,會拋出異常(如IllegalMonitorStateException-非法監(jiān)視器狀態(tài)異常),且condition實現(xiàn)類會記錄該事實。
7.在響應(yīng)信號過程中,condition實現(xiàn)類傾向于響應(yīng)中斷而不是方法正常返回或者超過給定截止時間。在任何情況下,condition實現(xiàn)類必須保證信號被重定向到其他等待線程(即,sinal發(fā)給其他線程以喚醒),如果有的話 。
8.參數(shù)
- deadline, 等待的絕對時間;
9.返回
- 如果經(jīng)過了等待時間返回false, 否則true;
10.拋出異常:
- InterruptedException-中斷異常,如果當(dāng)前線程被中斷(condition實現(xiàn)類支持線程掛起時中斷)
【2.6】void signal()
1.喚醒一個等待線程;
2.如果有多個線程在等待condition-條件,則其中一個線程將被選中進(jìn)行喚醒。那個選中的線程在從await()方法返回之前,必須重新獲取鎖;
3.實施注意事項
該方法被調(diào)用時, condition實現(xiàn)類可能要求(通常要求)當(dāng)前線程需要持有與condition對象關(guān)聯(lián)的鎖;condition實現(xiàn)類必須記錄這個先決條件以及在未持有鎖的情況下采取的任何動作;通常,會拋出異常,如IllegalMonitorStateException;
【2.7】void signalAll()
1.喚醒所有等待線程;
2.如果有線程在等待該條件,則所有等待線程都會被喚醒; 每個線程在從 await() 方法返回之前必須重新獲取鎖;
3.condition實現(xiàn)類注意事項
該方法被調(diào)用時, condition實現(xiàn)類可能要求(通常要求)當(dāng)前線程需要持有與condition對象關(guān)聯(lián)的鎖;condition實現(xiàn)類必須記錄這個先決條件以及在未持有鎖的情況下采取的任何動作;通常,會拋出異常,如IllegalMonitorStateException;
【3】方法總結(jié)
【3.2】等待方法
| void await() throws InterruptedException | 該方法導(dǎo)致當(dāng)前線程等待,直到收到信號或被中斷。 出現(xiàn)以下4種情況之一,線程恢復(fù)可運(yùn)行狀態(tài): 情況1,其他調(diào)用condition.signal(),且該線程被選中作為要喚醒的線程; 情況2,其他線程調(diào)用 condition.signalAll(), 喚醒所有等待線程; 情況3,發(fā)生中斷; 情況4,發(fā)送虛假喚醒; |
| void awaitUninterruptibly(); | 該方法導(dǎo)致當(dāng)前線程等待,直到收到信號; 出現(xiàn)以下3種情況之一,線程恢復(fù)可運(yùn)行狀態(tài): 情況1,其他調(diào)用condition.signal(),且該線程被選中作為要喚醒的線程; 情況2,其他線程調(diào)用 condition.signalAll(), 喚醒所有等待線程; 情況3,發(fā)送虛假喚醒; |
| long awaitNanos(long nanosTimeout) throws InterruptedException; | 該方法導(dǎo)致當(dāng)前線程等待,直到收到信號或被中斷或經(jīng)過給定等待時間。 出現(xiàn)以5種情況之一,線程恢復(fù)可運(yùn)行狀態(tài): 情況1,其他調(diào)用condition.signal(),且該線程被選中作為要喚醒的線程; 情況2,其他線程調(diào)用 condition.signalAll(), 喚醒所有等待線程; 情況3,發(fā)生中斷; 情況4,經(jīng)過給定的等待時間; 情況5,發(fā)送虛假喚醒; |
| boolean await(long time, TimeUnit unit) throws InterruptedException; | 導(dǎo)致當(dāng)前線程等待直到接收到信號,或被中斷,或經(jīng)過給定的等待時間。該方法等價于 awaitNanos(...) 方法, |
| boolean awaitUntil(Date deadline) throws InterruptedException; | 導(dǎo)致當(dāng)前線程等待直到收到信號,或中斷,或經(jīng)過了給定的截止日期。 出現(xiàn)以5種情況之一,線程恢復(fù)可運(yùn)行狀態(tài): 情況1,其他調(diào)用condition.signal(),且該線程被選中作為要喚醒的線程; 情況2,其他線程調(diào)用 condition.signalAll(), 喚醒所有等待線程; 情況3,發(fā)生中斷; 情況4,經(jīng)過指定的截止日期; 情況5,發(fā)送虛假喚醒; |
【3.2】喚醒方法
| void signal() | 喚醒一個等待線程; 如果有多個線程在等待condition-條件,則其中一個線程將被選中進(jìn)行喚醒。那個選中的線程在從await()方法返回之前,必須重新獲取鎖; |
| void signalAll() | 喚醒所有等待線程; 如果有線程在等待該條件,則所有等待線程都會被喚醒; 每個線程在從 await() 方法返回之前必須重新獲取鎖; |
總結(jié)
以上是生活随笔為你收集整理的java.util.concurrent.locks.Condition文档说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java.util.concurrent
- 下一篇: 60年代种族天赋(60级侏儒种族天赋)