新浪的博客編輯器貌似漂亮了不少,還增加了首行自動縮進(jìn)
1. 公平性
創(chuàng)建ReentrantLock對象時(shí),使用true參數(shù)可以激活公平鎖策略(fair locking policy):
Lock fareLock = new ReentrantLock(true);
公平鎖有助于等待時(shí)間最長的線程的恢復(fù)運(yùn)行,當(dāng)然這種機(jī)制也影響了程序性能。公平鎖比普通鎖慢很多,因此默認(rèn)關(guān)閉。
2. 鎖測試、超時(shí)
線程調(diào)用lock方法的時(shí)候很有可能停滯,可以使用tryLock()方法代替。獲得鎖成功,tryLock返回true,反之返回false,且線程可以繼續(xù)運(yùn)行。
可以在tryLock中增加時(shí)限參數(shù),如
if (myLock.tryLock(1000, TimeUnit.MILLISECONDS) ...
表示時(shí)限為1000毫秒,TimeUnit是一個枚舉類,它的值有SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS。
帶時(shí)限參數(shù)的tryLock方法和lock方法一樣遵循公平原則,但是無參的tryLock卻不會,不過可以用tryLock(0, TimeOut.SECONES)代替。
lock方法無法被打斷,如果一個線程在等待鎖的時(shí)候被中斷,它會繼續(xù)處于停滯狀態(tài),知道獲得鎖為止。而使用帶時(shí)限的tryLock方法,如果線程在等待時(shí)被中斷,它會拋出InterruptedException異常。這很有用,可以防止程序鎖死的發(fā)生。
類似的還有l(wèi)ockInterruptibly,和tryLock很相似,只是時(shí)限無限長。
Condition也可以設(shè)置時(shí)限:
myCondition.await(100, TimeUnit.MILLISECONDS);
這樣await方法有三種結(jié)束的可能:其他線程調(diào)用的signal或signalAll方法激活該線程;時(shí)限到;線程被中斷(拋出InterruptedException)。
對于第三種可能,如果不想被中斷(一般很少這樣),調(diào)用awaitUninterruptibly方法。
3. 讀寫鎖
ReentrantReadWriteLock類用于許多線程從一個數(shù)據(jù)源讀寫的情況。readLock()和writeLock()返回內(nèi)置的讀寫鎖。
4. 為什么stop和suspend方法要被廢棄
兩個方法有一個共同點(diǎn):都試圖未經(jīng)其他線程允許就控制它們的行為。
首先來看stop方法,這個方法結(jié)束了所有執(zhí)行中的方法,包括run方法,當(dāng)一個線程被停止的時(shí)候,它立即放棄了所有它鎖住的對象,這會使那些對象處于非正常狀態(tài)。如轉(zhuǎn)帳的transferThread在取出資金后存入資金前被停止,就會產(chǎn)生事故。因?yàn)橐粋€線程試圖結(jié)束另一個線程的時(shí)候,它并不知道此時(shí)該行為是否安全。
然后是suspend方法,suspend方法并不會損害對象。但是當(dāng)你調(diào)用suspend方法掛起一個線程時(shí),這個線程擁有的鎖也就同時(shí)被掛起了,此時(shí)如果調(diào)用suspend方法的線程試圖獲得那把鎖,那么整個程序就會鎖死:被掛起的線程需要恢復(fù),能夠恢復(fù)它的線程因?yàn)殒i而停滯。
這種情況在GUI中尤為常見,例如銀行用戶界面有暫停和繼續(xù)兩個按鈕,暫停按鈕能夠掛起所有運(yùn)行中的線程,另外paintComponent方法能夠畫出每個帳號的圖表。
假設(shè)某個線程獲得了bank對象的鎖,此時(shí)用戶按下了暫停按鈕,所有的轉(zhuǎn)帳線程掛起,其中一個擁有bank的鎖。由于某個原因,帳號圖表需要重繪,調(diào)用了paintComponent方法,后者調(diào)用了getBalances方法,又因?yàn)闊o法獲得bank對象的鎖,程序鎖死。而此時(shí)用戶自然也無法按下繼續(xù)按鈕。
如果想安全地使用掛起功能,可以自己設(shè)計(jì)一個suspendRequested變量。
public void run()
{
while (. . .)
{
. . .
if (suspendRequested)
{
suspendLock.lock();
try { while (suspendRequested) suspendCondition.await(); }
finally { suspendLock.unlock(); }
}
}
}
public void requestSuspend() { suspendRequested = true; }
public void requestResume()
{
suspendRequested = false;
suspendLock.lock();
try { suspendCondition.signalAll(); }
finally { suspendLock.unlock(); }
}
private volatile boolean suspendRequested = false;
private Lock suspendLock = new ReentrantLock();
private Condition suspendCondition = suspendLock.newCondition();