2017-09-25 35 views
2

tryLock()可能無法獲取鎖定。因此,如果我們使用返回值進行工作,我們可能根本就沒有做這項工作。tryLock()在循環?

Lock lock = new ReentrantLock(); 
boolean isLocked = lock.tryLock(); 

if (isLocked) { 
    try { 
     doWork(); 
    } finally { 
     lock.unlock(); 
    } 
} 

一個​​將阻塞,直到鎖被收購,所以我們知道doWork()將最終完成。

那麼,是不是正確的,我們應該tryLock()一個循環中,直到獲取鎖?

boolean isLocked = false; 

while (!isLocked) { 
    isLocked = lock.tryLock(); 
    Thread.sleep(100); 
} 

if (isLocked) { 
    try { 
     doWork(); 
    } finally { 
     lock.unlock(); 
    } 
} 
+1

,如果你得到了鎖你應該肯定睡不着。 – EJP

回答

2

幾乎從未,沒有。

如果您需要需要來獲取鎖定,您只需使用lock()調用即可。如果可用,這將立即獲得,否則等待。在tryLock()反覆循環也有等待鎖,如果沒有可用的效果,但沒有允許適當的操作系統控制的阻塞和等待線程甦醒。相反,等待的線程將繼續佔用CPU,在等待鎖釋放的同時,耗費CPU時間和功耗。

在最糟糕的情況之一,擁有該鎖的線程可能會被上下文切換出來並等待可用的CPU繼續運行,但由於正在由線程繁忙循環使用,CPU不可用在tryLock。這幾乎形式的臨時僵局 - 暫時的,因爲最終tryLock線程將利用其量子並關閉計劃,但整個過程可能需要很多個數量級長於使用lock()的通常的做法。

所有這一切說tryLock()具有非常有限的用途。如果您在緊密循環中使用tryLock(),則幾乎肯定會出現錯誤。當你不需要確實需要鎖定並做其他工作時,最好使用它,而且性能很重要。

如果你有幾個獨立的對象執行相同的操作一個例子可能是,每一個都有自己的鎖。默認方法將簡單地依次爲每個對象lock()unlock()。這可能是一種更快的辦法是先tryLock()每個對象,任何更新,而您獲得鎖(也許你做的比這一次以上),並返回到lock()任何對象,你錯過了第一次。通過最初不等待任何鎖定,只需繼續其餘的對象,就可以在競爭系統中實現更高的更新速率。

tryLock()可能有用的另一種情況是,您可以以多種方式實現相同的效果。想象一下,例如某種「分佈式計數器」,其中有一個邏輯計數器實現爲N個獨立的等價計數器,每個計數器都有自己的鎖。邏輯計數器的只是N個底層計數器的總和。要增加計數器(例如),您只需增加N個計數器中的任何一個。在這種情況下,有人試圖更新計數器可以只是tryLock()底層計數器,直到他找到一個「可用」並對其進行修改。這可能比只有一個鎖的單個櫃檯更好。


當然,對於一個簡單的計數器你可能會使用原子整數,如AtomicInteger,或者更好,LongAdder - 但對於更復雜的結構,這可能是現實的。

如果tryLock()線程具有比線程擁有鎖更高的優先級,並調度策略嚴格將優先級時,會發生更糟糕的情況下(即,低優先級的線程從未搶佔更高優先級的)像SCHED_FIFOSCHED_RR。在這種情況下,優先級較高的線程可能會無限期地旋轉tryLock(),因爲擁有它的較低優先級的線程永遠不會由於存在可運行的較高優先級線程而被喚醒。所以你甚至可能會陷入僵局。

+0

我明白了。但這意味着'tryLock()'只能用於'doWork',如果鎖定不可用,可能會跳過。這是我的印象,我需要在這裏確認。這與'lock()'不同,'lock()'最終會得到鎖,因此也是'doWork'。 – jforex78

+0

其實我在這裏看到一個有趣的答案 - https://stackoverflow.com/a/27603051/8441607 - 只有在獲取鎖定是可選的時候才應該使用'tryLock()'。除了@BeeOnRope所說的外,這或多或少證實了這一點。謝謝。 – jforex78

+0

@ jforex78 - 我通過回答更新,解釋一個可能使用'tryLock()'的場景。通常的情況正是你所說的:出於某種原因,你不需要做這項工作,也許是因爲你可以稍後做,或者以另一種方式達到相同的效果。 – BeeOnRope

0

tryLock()是在一個線程中使用,可以做,有時一些其他有益的工作時,它無法獲取鎖:

while (there_still_is_work_to_be_done) { 
    if (lock.tryLock()) { 
     try { 
      doSomeWorkThatNeedsTheLockToBeLocked(); 
     finally { 
      lock.unlock(); 
     } 
    } 

    doSomeOtherUsefulWork(); 
    waitABit(); 
} 
+0

懂了......... – jforex78