2017-01-19 48 views
1

只有當一個或多個線程通過可鎖定資源創建循環的可能性創建循環依賴時,死鎖似乎纔有可能。可以通過在java鎖上始終使用tryLock來防止死鎖嗎?

一種選擇是通過仔細的靜態分析或通過獲取鎖的設計模式來避免這些週期。

但是,我們可以通過在鎖定界面上使用tryLock來防止死鎖嗎? tryLock試圖以原子方式獲取鎖,如果成功則返回true,如果它已經鎖定,則返回false,以便我們可以簡單地跳過代碼。

int sharedStateA = 0; 
int sharedStateB = 0; 
Lock lockA = new ReentrantLock(); 
Lock lockB = new ReentrantLock(); 

// possible deadlock safe solution 

// executed by thread 1 
void deadLockSafeUpdateAthenB(){ 
    try { 
     if (lockA.tryLock()){ 
      sharedStateA = sharedStateA + 1; 

      try { 
       if (lockB.tryLock()){ 
        sharedStateB = sharedStateB + 1; 
       } 
      } finally { 
       lockB.unlock(); 
      } 
     } 
    } finally { 
     lockA.unlock(); 
    } 
} 

// executed by thread 2 
void deadLockSafeUpdateBthenA(){ 
    try { 
     if (lockB.tryLock()){ 
      sharedStateB = sharedStateB + 1; 

      try { 
       if (lockA.tryLock()){ 
        sharedStateA = sharedStateA + 1; 
       } 
      } finally { 
       lockA.unlock(); 
      } 
     } 
    } finally { 
     lockB.unlock(); 
    } 
} 
+1

就死鎖而言應該是安全的,但您必須確保生成的行爲是正確的。 – shmosel

+0

您是否知道,如果鎖定未獲取,狀態更新可能不會發生?我很難想象這種方法何時可能有用 – Anton

回答

1

您與Lock.tryLock()代碼是死鎖安全的,但你應該嘗試使用其他方法,

public boolean tryLock(long timeout, 
       TimeUnit unit) 

如果你的線程有運行時間短,。呼叫 - tryLock(0,TimeUnit.SECONDS)Lock.tryLock()更好,因爲它遵守公平性策略,即鎖定等待隊列被授予,而tryLock()不會兌現。

即使靜態分析告訴我們一個代碼容易出現死鎖,但並不總是需要死鎖代碼實際上會產生死鎖,因爲它的所有不幸的定時遊戲因此您的目標與tryLock()應該在功能上產生相同程序與死鎖易發生的代碼一樣,假設死鎖沒有發生。

修復一個問題不應該引入其他問題,並且在你的代碼中,看起來很可能在某些不幸的時機,一個線程可能根本不會執行,所以我建議使用定時trylock而不是闖關trylock,如果它強制鎖收購將按照該順序進行。

希望它有幫助!