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