java.util.concurrent.locks 介面 Condition Condition 將 Object 監視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意 Lock 實現組合使用,為每個對象提供多個等待 set(wait-set) ...
java.util.concurrent.locks 介面 Condition
public interface Condition
Condition
將 Object
監視器方法(wait
、notify
和 notifyAll
)分解成截然不同的對象,以便通過將這些對象與任意 Lock
實現組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock
替代了 synchronized
方法和語句的使用,Condition
替代了 Object 監視器方法的使用。
條件(也稱為條件隊列 或條件變數)為線程提供了一個含義,以便在某個狀態條件現在可能為 true 的另一個線程通知它之前,一直掛起該線程(即讓其“等待”)。因為訪問此共用狀態信息發生在不同的線程中,所以它必須受保護,因此要將某種形式的鎖與該條件相關聯。等待提供一個條件的主要屬性是:以原子方式 釋放相關的鎖,並掛起當前線程,就像 Object.wait
做的那樣。
Condition
實例實質上被綁定到一個鎖上。要為特定 Lock
實例獲得 Condition
實例,請使用其 newCondition()
方法。
作為一個示例,假定有一個綁定的緩衝區,它支持 put
和 take
方法。如果試圖在空的緩衝區上執行 take
操作,則在某一個項變得可用之前,線程將一直阻塞;如果試圖在滿的緩衝區上執行 put
操作,則在有空間變得可用之前,線程將一直阻塞。我們喜歡在單獨的等待 set 中保存 put
線程和 take
線程,這樣就可以在緩衝區中的項或空間變得可用時利用最佳規劃,一次只通知一個線程。可以使用兩個 Condition
實例來做到這一點。
class BoundedBuffer { 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) notFull.await(); items[putptr] = x; 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(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
(ArrayBlockingQueue
類提供了這項功能,因此沒有理由去實現這個示例類。)
Condition
實現可以提供不同於 Object
監視器方法的行為和語義,比如受保證的通知排序,或者在執行通知時不需要保持一個鎖。如果某個實現提供了這樣特殊的語義,則該實現必須記錄這些語義。
註意,Condition
實例只是一些普通的對象,它們自身可以用作 synchronized
語句中的目標,並且可以調用自己的 wait
和 notification
監視器方法。獲取 Condition
實例的監視器鎖或者使用其監視器方法,與獲取和該 Condition
相關的 Lock
或使用其 waiting
和 signalling
方法沒有什麼特定的關係。為了避免混淆,建議除了在其自身的實現中之外,切勿以這種方式使用 Condition
實例。
除非另行說明,否則為任何參數傳遞 null
值將導致拋出 NullPointerException
。
實現註意事項
在等待 Condition
時,允許發生“虛假喚醒”,這通常作為對基礎平臺語義的讓步。對於大多數應用程式,這帶來的實際影響很小,因為 Condition
應該總是在一個迴圈中被等待,並測試正被等待的狀態聲明。某個實現可以隨意移除可能的虛假喚醒,但建議應用程式程式員總是假定這些虛假喚醒可能發生,因此總是在一個迴圈中等待。
三種形式的條件等待(可中斷、不可中斷和超時)在一些平臺上的實現以及它們的性能特征可能會有所不同。尤其是它可能很難提供這些特性和維護特定語義,比如排序保證。更進一步地說,中斷線程實際掛起的能力在所有平臺上並不是總是可行的。
因此,並不要求某個實現為所有三種形式的等待定義完全相同的保證或語義,也不要求其支持中斷線程的實際掛起。
要求實現清楚地記錄每個等待方法提供的語義和保證,在某個實現不支持中斷線程的掛起時,它必須遵從此介面中定義的中斷語義。
由於中斷通常意味著取消,而又通常很少進行中斷檢查,因此實現可以先於普通方法的返回來對中斷進行響應。即使出現在另一個操作後的中斷可能會釋放線程鎖時也是如此。實現應記錄此行為。
- 從以下版本開始:
- 1.5
方法摘要 | |
---|---|
void |
await() 造成當前線程在接到信號或被中斷之前一直處於等待狀態。 |
boolean |
await(long time, TimeUnit unit) 造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處於等待狀態。 |
long |
awaitNanos(long nanosTimeout) 造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處於等待狀態。 |
void |
awaitUninterruptibly() 造成當前線程在接到信號之前一直處於等待狀態。 |
boolean |
awaitUntil(Date deadline) 造成當前線程在接到信號、被中斷或到達指定最後期限之前一直處於等待狀態。 |
void |
signal() 喚醒一個等待線程。 |
void |
signalAll() 喚醒所有等待線程。 |
方法詳細信息 |
---|
await
void await() throws InterruptedException
- 造成當前線程在接到信號或被中斷之前一直處於等待狀態。
與此
Condition
相關的鎖以原子方式釋放,並且出於線程調度的目的,將禁用當前線程,且在發生以下四種情況之一 以前,當前線程將一直處於休眠狀態:- 其他某個線程調用此
Condition
的signal()
方法,並且碰巧將當前線程選為被喚醒的線程;或者 - 其他某個線程調用此
Condition
的signalAll()
方法;或者 - 其他某個線程中斷當前線程,且支持中斷線程的掛起;或者
- 發生“虛假喚醒”
在所有情況下,在此方法可以返回當前線程之前,都必須重新獲取與此條件有關的鎖。線上程返回時,可以保證 它保持此鎖。
如果當前線程:
- 在進入此方法時已經設置了該線程的中斷狀態;或者
- 在支持等待和中斷線程掛起時,線程被中斷,
則拋出
InterruptedException
,並清除當前線程的中斷狀態。在第一種情況下,沒有指定是否在釋放鎖之前發生中斷測試。實現註意事項
假定調用此方法時,當前線程保持了與此
Condition
有關聯的鎖。這取決於確定是否為這種情況以及不是時,如何對此作出響應的實現。通常,將拋出一個異常(比如IllegalMonitorStateException
)並且該實現必須對此進行記錄。與響應某個信號而返回的普通方法相比,實現可能更喜歡響應某個中斷。在這種情況下,實現必須確保信號被重定向到另一個等待線程(如果有的話)。
- 其他某個線程調用此
- 拋出:
InterruptedException
- 如果當前線程被中斷(並且支持中斷線程掛起)
awaitUninterruptibly
void awaitUninterruptibly()
- 造成當前線程在接到信號之前一直處於等待狀態。
與此條件相關的鎖以原子方式釋放,並且出於線程調度的目的,將禁用當前線程,且在發生以下三種情況之一 以前,當前線程將一直處於休眠狀態:
- 其他某個線程調用此
Condition
的signal()
方法,並且碰巧將當前線程選為被喚醒的線程;或者 - 其他某個線程調用此
Condition
的signalAll()
方法;或者 - 發生“虛假喚醒”
在所有情況下,在此方法可以返回當前線程之前,都必須重新獲取與此條件有關的鎖。線上程返回時,可以保證 它保持此鎖。
如果在進入此方法時設置了當前線程的中斷狀態,或者在等待時,線程被中斷,那麼在接到信號之前,它將繼續等待。當最終從此方法返回時,仍然將設置其中斷狀態。
實現註意事項
假定調用此方法時,當前線程保持了與此
Condition
有關聯的鎖。這取決於確定是否為這種情況以及不是時,如何對此作出響應的實現。通常,將拋出一個異常(比如IllegalMonitorStateException
)並且該實現必須對此進行記錄。 - 其他某個線程調用此
awaitNanos
long awaitNanos(long nanosTimeout) throws InterruptedException
- 造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處於等待狀態。
與此條件相關的鎖以原子方式釋放,並且出於線程調度的目的,將禁用當前線程,且在發生以下五種情況之一 以前,當前線程將一直處於休眠狀態:
- 其他某個線程調用此
Condition
的signal()
方法,並且碰巧將當前線程選為被喚醒的線程;或者 - 其他某個線程調用此
Condition
的signalAll()
方法;或者 - 其他某個線程中斷當前線程,且支持中斷線程的掛起;或者
- 已超過指定的等待時間;或者
- 發生“虛假喚醒”。
在所有情況下,在此方法可以返回當前線程之前,都必須重新獲取與此條件有關的鎖。線上程返回時,可以保證 它保持此鎖。
如果當前線程:
- 在進入此方法時已經設置了該線程的中斷狀態;或者
- 在支持等待和中斷線程掛起時,線程被中斷,
則拋出
InterruptedException
,並且清除當前線程的已中斷狀態。在第一種情況下,沒有指定是否在釋放鎖之前發生中斷測試。在返回時,該方法返回了所剩毫微秒數的一個估計值,以等待所提供的
nanosTimeout
值的時間,如果超時,則返回一個小於等於 0 的值。可以用此值來確定在等待返回但某一等待條件仍不具備的情況下,是否要再次等待,以及再次等待的時間。此方法的典型用法採用以下形式:synchronized boolean aMethod(long timeout, TimeUnit unit) { long nanosTimeout = unit.toNanos(timeout); while (!conditionBeingWaitedFor) { if (nanosTimeout > 0) nanosTimeout = theCondition.awaitNanos(nanosTimeout); else return false; } // ... }
設計註意事項:此方法需要一個 nanosecond 參數,以避免在報告剩餘時間時出現截斷錯誤。在發生重新等待時,這種精度損失使得程式員難以確保總的等待時間不少於指定等待時間。
實現註意事項
假定調用此方法時,當前線程保持了與此
Condition
有關聯的鎖。這取決於確定是否為這種情況以及不是時,如何對此作出響應的實現。通常會拋出一個異常(比如IllegalMonitorStateException
)並且該實現必須對此進行記錄。與響應某個信號而返回的普通方法相比,或者與指示所使用的指定等待時間相比,實現可能更喜歡響應某個中斷。在任意一種情況下,實現必須確保信號被重定向到另一個等待線程(如果有的話)。
- 其他某個線程調用此
- 參數:
nanosTimeout
- 等待的最長時間,以毫微秒為單位- 返回:
nanosTimeout
值減去花費在等待此方法的返回結果的時間的估算。正值可以用作對此方法進行後續調用的參數,來完成等待所需時間結束。小於等於零的值表示沒有剩餘時間。- 拋出:
InterruptedException
- 如果當前線程被中斷(並且支持中斷線程掛起)
await
boolean await(long time, TimeUnit unit) throws InterruptedException
- 造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處於等待狀態。此方法在行為上等效於:
awaitNanos(unit.toNanos(time)) > 0
- 參數:
time
- 最長等待時間unit
-time
參數的時間單位- 返回:
- 如果在從此方法返回前檢測到等待時間超時,則返回
false
,否則返回true
- 拋出:
InterruptedException
- 如果當前線程被中斷(並且支持中斷線程掛起)
awaitUntil
boolean awaitUntil(Date deadline) throws InterruptedException
- 造成當前線程在接到信號、被中斷或到達指定最後期限之前一直處於等待狀態。
與此條件相關的鎖以原子方式釋放,並且出於線程調度的目的,將禁用當前線程,且在發生以下五種情況之一 以前,當前線程將一直處於休眠狀態:
- 其他某個線程調用此
Condition
的signal()
方法,並且碰巧將當前線程選為被喚醒的線程;或者 - 其他某個線程調用此
Condition
的signalAll()
方法;或者 - 其他某個線程中斷當前線程,且支持中斷線程的掛起;或者
- 指定的最後期限到了;或者
- 發生“虛假喚醒”。
在所有情況下,在此方法可以返回當前線程之前,都必須重新獲取與此條件有關的鎖。線上程返回時,可以保證 它保持此鎖。
如果當前線程:
- 在進入此方法時已經設置了該線程的中斷狀態;或者
- 在支持等待和中斷線程掛起時,線程被中斷,
則拋出
InterruptedException
,並且清除當前線程的已中斷狀態。在第一種情況下,沒有指定是否在釋放鎖之前發生中斷測試。返回值指示是否到達最後期限,使用方式如下:
synchronized boolean aMethod(Date deadline) { boolean stillWaiting = true; while (!conditionBeingWaitedFor) { if (stillWaiting) stillWaiting = theCondition.awaitUntil(deadline); else return false; } // ... }
實現註意事項
假定調用此方法時,當前線程保持了與此
Condition
有關聯的鎖。這取決於確定是否為這種情況以及不是時,如何對此作出響應的實現。通常,將拋出一個異常(比如IllegalMonitorStateException
)並且該實現必須對此進行記錄。與響應某個信號而返回的普通方法相比,或者與指示是否到達指定最終期限相比,實現可能更喜歡響應某個中斷。在任意一種情況下,實現必須確保信號被重定向到另一個等待線程(如果有的話)。
- 其他某個線程調用此
- 參數:
deadline
- 一直處於等待狀態的絕對時間- 返回:
- 如果在返回時已經到達最後期限,則返回
false
,否則返回true
- 拋出:
InterruptedException
- 如果當前線程被中斷(並且支持中斷線程掛起)
signal
void signal()
- 喚醒一個等待線程。
如果所有的線程都在等待此條件,則選擇其中的一個喚醒。在從
await
返回之前,該線程必須重新獲取鎖。
signalAll
void signalAll()
- 喚醒所有等待線程。
如果所有的線程都在等待此條件,則喚醒所有線程。在從
await
返回之前,每個線程都必須重新獲取鎖。