[TOC]
4.1 模式簡(jiǎn)介
- 我正坐在餐館中,合計(jì)著吃點(diǎn)什么。想好之后,我舉起手示意服務(wù)員點(diǎn)菜。于是,看到我舉手的服務(wù)員就向我走來(lái)點(diǎn)菜。這時(shí),另一位服務(wù)員也看到我舉手示意了,但他看到已經(jīng)有一位服務(wù)員走向了我,所以就沒(méi)有再過(guò)來(lái)。
- 如果現(xiàn)在不適合執(zhí)行這個(gè)操作,或者沒(méi)必要執(zhí)行這個(gè)操作,就停止處理,直接返回——這就是Balking模式。
- 所謂Balk,就是 “停止并返回” 的意思。
- Balking 模式與Guarded Suspension模式一樣,也存在守護(hù)條件。在Balking模式中,如果守護(hù)條件不成立,則立即中斷處理。這與Guarded Suspension模式有所不同,因?yàn)镚uarded Suspension模式是一直等待至可以運(yùn)行。
4.3 Balking模式中的角色
4.3.1 GuardedObject
- GuardedObject角色是一個(gè)擁有被防護(hù)的方法(guardedMethod)的類(lèi)。當(dāng)線程執(zhí)行g(shù)uardedMethod方法時(shí),若守護(hù)條件成立,則執(zhí)行實(shí)際的處理。而當(dāng)守護(hù)條件不成立時(shí),則不執(zhí)行實(shí)際的處理,直接返回。守護(hù)條件的成立與否,會(huì)隨著GuardedObject角色的狀態(tài)變化而發(fā)生變化。
- 除了guardedMethod之外,GuardedObject角色還有可能有其他來(lái)改變狀態(tài)的方法(stateChangingMethod)。
4.3.2 類(lèi)圖和Timethreads圖

類(lèi)圖

Timethreads圖
4.4 拓展思路的要點(diǎn)
4.4.1 何時(shí)使用
- 并不需要執(zhí)行時(shí)。
- 在這里執(zhí)行balk能夠提高程序性能。
- 不需要等待守護(hù)條件成立時(shí)。
- Balking模式的特點(diǎn)就是“不進(jìn)行等待”。若守護(hù)條件不成立時(shí),想要立即返回并進(jìn)入下一個(gè)操作,就可以使用Balking模式。這能夠提高程序的響應(yīng)性。
- 守護(hù)條件僅在第一次成立時(shí)。
- 具體實(shí)例經(jīng)常是實(shí)例的初始化和終止處理等。例如下列代碼中的Something類(lèi)。在這里,initialized字段表示初始化是否已經(jīng)完成。當(dāng)init方法被調(diào)用后,它會(huì)首先來(lái)檢查initialized字段。
- 如果initialized字段的值為true,就表明字段已經(jīng)初始化了,此時(shí)需要使用return執(zhí)行balk(也可以設(shè)計(jì)成拋出異常)。
- 如果initialized字段的值為false,就需要調(diào)用doInit方法執(zhí)行實(shí)際的初始化處理,然后將initialized字段設(shè)置為true,來(lái)記錄“初始化已經(jīng)完成了”這一事實(shí)(這相當(dāng)于沒(méi)有stateChangingMethod方法的情況)。
public class P448_Reorder.Something
{
private boolean initialized = false;
public synchronized void init()
{
if (initialized) // 此處不能使用while,因?yàn)閕nitialized字段一旦為true就不會(huì)再變?yōu)閒alse
{
return;
}
doInit();
initialized = true;
}
private void doInit()
{
// 實(shí)際的初始化處理
}
}
4.4.2 balk結(jié)果的表示方式
- 忽略balk。
- 通過(guò)返回值來(lái)表示balk。
- 通過(guò)異常來(lái)表示balk的發(fā)生。
4.6 超時(shí)
4.6.1 Timeout
- 在Balking模式中,當(dāng)守護(hù)條件不成立時(shí),線程會(huì)直接balk并返回。
- 在Guarded Suspension模式中,當(dāng)守護(hù)條件不成立時(shí),線程會(huì)一直等待到成立為止。
- 介于 “直接balk并返回” 和 “等待到守護(hù)條件成立為止” 這兩種極端的處理方法之間,還有一種處理方法,那就是 “在守護(hù)條件成立之前等待一段時(shí)間”。在守護(hù)條件成立之前等待一段時(shí)間,如果到時(shí)條件還未成立,則直接balk。我們將這種處理稱(chēng)為guarded timed 或timeout。
4.6.2 wait何時(shí)終止
- notify方法執(zhí)行時(shí)。
- notifyAll方法執(zhí)行時(shí)。
- interrupt方法執(zhí)行時(shí)。
- 超時(shí)發(fā)生時(shí)。
其中notify和notifyAll這兩個(gè)方法是用于調(diào)用實(shí)例的,而interrupt方法是用于調(diào)用線程的。當(dāng)被interrupt時(shí),等待隊(duì)列中的線程(與被notify、notifyAll時(shí)一樣)會(huì)重新獲取obj的鎖,然后拋出InterruptedException異常。
4.6.3 synchronized和wait狀態(tài)的區(qū)別
對(duì)于線程的下列兩種狀態(tài):
- 想要使用synchronized獲取鎖但處于阻塞狀態(tài)
- 執(zhí)行wait并進(jìn)入等待隊(duì)列的狀態(tài)
在這兩種狀態(tài)下,線程都是不運(yùn)行的,這一點(diǎn)兩者非常相似,但也存在不同:
- 我們無(wú)法讓狀態(tài)1下的線程發(fā)生超時(shí)。這是因?yàn)椋瑂ynchronized方法和synchronized代碼塊都無(wú)法設(shè)置超時(shí)時(shí)間。
- 另外,即使對(duì)狀態(tài)1下的線程執(zhí)行interrupt,也不會(huì)拋出InterruptedException異常。線程必須在獲取鎖并進(jìn)入synchronized之后,調(diào)用那些會(huì)注意著中斷狀態(tài)的方法,如wait、sleep、join等,或者使用isInterrupted方法或interrupted方法檢查中斷狀態(tài),自己拋出去。