java併發多線程顯式鎖Condition條件簡介分析與監視器 多線程下篇(四)

Lock接口提供了方法Condition newCondition();用於獲取對應鎖的條件,能夠在這個條件對象上調用監視器方法
能夠理解爲,本來藉助於synchronized關鍵字以及鎖對象,配備了一個監視器
而顯式鎖Lock與Condition則針對於一個鎖對象,提供了多個監視器
儘管是提供了多個監視器,可是須要記住,是Lock接口提供方法纔可以獲取到條件對象,因此這些條件對象仍舊是綁定到某一把鎖上的
我相信,只要理解了監視器的概念,對於Condition理解起來是不會存在任何難度的,由於自己就是另一種實現方式
image_5c81c4bd_31bc
從下圖能夠直觀的感覺到Condition是做爲Object監視器方法的另外實現
wait在這邊叫作await
notify在這邊叫作signal
image_5c81c4bd_1aeb

等待

await

在監視器上等待
void await() throws InterruptedException;   ,看得出來,此方法是支持中斷的
除非發生如下事件,不然將會持續等待
  • 其餘某個線程調用此 Condition 的 signal() 方法,而且碰巧喚醒的是該線程
  • 其餘某個線程調用此 Condition 的 signalAll() 方法;
  • 其餘某個線程中斷當前線程
  • 「虛假喚醒」 

awaitUninterruptibly

不支持中斷的await方法,void awaitUninterruptibly();
從await()的介紹中看得出來,除非發生提到的四種狀況,不然將會是等待狀態
而void awaitUninterruptibly();則是await()的不可中斷版本,也就是隻會有三種狀況會跳出等待
  • 其餘某個線程調用此 Condition 的 signal() 方法,而且碰巧喚醒的是該線程
  • 其餘某個線程調用此 Condition 的 signalAll() 方法;
  • 其餘某個線程中斷當前線程
  • 「虛假喚醒」  

awaitNanos

    long awaitNanos(long nanosTimeout) throws InterruptedException;
支持設置超時的等待,參數爲等待的納秒的long型數值
他在基於await的前提下,新增長了超時跳出,不然將會一直等待,他的跳出條件以下
  • 其餘某個線程調用此 Condition 的 signal() 方法,而且碰巧喚醒的是該線程
  • 其餘某個線程調用此 Condition 的 signalAll() 方法;
  • 其餘某個線程中斷當前線程
  • 「虛假喚醒」  
  • 已超過指定的等待時間新增
返回值
須要注意的是此方法的返回值,是一個long
咱們設置了一個超時時間,那麼到底用了多少秒,還剩下多少秒?這個返回值就是這意思:
(nanosTimeout - 實際花費時間)的估算值,若是小於等於0,表示沒有剩餘時長;若是大於0,能夠用來肯定若是等待返回了是否還須要繼續等待?
好比,你在等朋友A,A說你等我一小時,因而你去睡覺了,結果你睡了半小時就被叫醒了,那麼跟你原本要等的時間還差半小時
那還要不要繼續等了?仍是必定要等到總共一小時呢?
典型用法(來自API):
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();
}
}
上面的方法中,若是條件仍舊不知足,可是等待結束了(也就是等待了足夠多的時間了),直接返回false;不然將會繼續執行,直到等到最後一刻
ps:這種代碼風格也就JDK常寫,否者這種if形式,估計要被項目經理罵

await(long time, TimeUnit unit)

    boolean await(long time, TimeUnit unit) throws InterruptedException;
此方法也是設置超時時長的等待方法,第一個參數爲時長個數,第二個參數爲第一個參數的單位
他至關於awaitNanos方法的封裝(此處是邏輯上看起來,而不是說就是這個方法的封裝)
awaitNanos(unit.toNanos(time)) > 0
因此返回類型爲boolean,顯然true表示沒有等待足夠的時間;,false 表示等待了足夠時間,也就是等待超時

awaitUntil

    boolean awaitUntil(Date deadline) throws InterruptedException;
awaitUntil相似於await(long time, TimeUnit unit),只不過不是設置超時時長,而是設置截止日期
邏輯上能夠把他們理解爲一回事,若是沒有等待足夠時長,那麼返回true;若是等待超時那麼返回false
經常使用的邏輯(來自API)
boolean aMethod(Date deadline) {
boolean stillWaiting = true;
lock.lock();
try {
while (!conditionBeingWaitedFor()) {
if (!stillWaiting)
return false;
stillWaiting = theCondition.awaitUntil(deadline);
}
// ...
} finally {
lock.unlock();
}
}
上面的代碼中,若是等待了足夠的時長(等待超時),那麼就會返回false;若是還有剩餘時間,繼續等待
 
普通的await()方法和awaitUninterruptibly都是直白的等待,一個支持中斷,一個不支持中斷
有超時設置的三個方法:
awaitNanos、await(long time, TimeUnit unit)、awaitUntil
都是在await()的基礎上對超時時長或者截止日期的設置使用
不過這幾個方法會返回剩餘的超時時長或者使用boolean指示是否還有剩餘
因此若是條件不知足,若是還沒等夠時間,能夠控制繼續等待或者退出
而對於Object提供的wait方法,就不能作到這麼靈活的控制,要麼就條件不知足繼續等待,要麼醒來後繼續作別的事情,沒辦法相對準確的控制「必需要等待必定的時長」,由於若是wait(一小時),5分鐘後,被喚醒了,這個用掉了的五分鐘(或者說還剩餘55分鐘,是不知道的)

喚醒

關於喚醒有與Object提供的相似的兩個方法,他們的邏輯含義也是同樣的,喚醒一個或者喚醒全部,概念上並無太多須要注意的事情
void signal();
void signalAll();

總結

Condition自己就是Object中監視器概念的另外實現,因此監視器方法調用,也須要持有鎖,也就是說:
調用Condition的await()和signal()等方法,都必須在lock保護以內,就是說必須在lock.lock()和lock.unlock之間纔可使用
await系列方法相對於Object提供了更加靈活的使用形式,signal和signalAll的邏輯含義能夠認爲徹底一致
另外須要注意await方法與Object中的wait同樣,都會釋放當前持有的鎖,因此醒來以後,會須要從新獲取鎖
相關文章
相關標籤/搜索