簡體   English   中英

了解鎖類與同步

[英]Understanding Lock class vs synchronization

在 Java Concurrency In Practice 中,我提出了避免死鎖的技術。 他提出在我們需要獲取多個鎖時使用tryLock()來保證一致性。 如下:

public void m(MyObject o1, MyObject o2){
    synchronized(o1){
        synchornized(o2){
            //...
        }
    }
}

相反,我們最好使用這個:

public void m(MyObject o1, MyObject o2){
    while(true){
        if(o1.lock.tryLock(){
             try{
                 if(o2.lock.tryLock(){ 
                     try{
                          //...
                     } finally {
                          o2.lock.unlock();
                     }
                 }
            } finally { 
                  o2.lock.unlock()
            }
        }
    }
}

現在他說:

這種技術只有在同時獲取兩個鎖時才有效; 如果由於方法調用的嵌套而獲取了多個鎖,則不能只釋放外部鎖,即使您知道自己持有它。

這不是很明顯。 為什么在方法中調用方法時不能使用 this? 能給我舉個例子嗎?

我剛剛查看了這本書,發現引用的語句是在定時鎖的上下文中進行的(使用tryLock(long time, TimeUnit unit) ),但我認為它也適用於您的tryLock()示例。

從理論上講,您仍然可以將此技術與嵌套方法調用一起使用,但它會很快變得笨拙。 讓我們考慮一個簡單的例子,您嘗試在方法foo(Lock lock)獲取一些鎖,如果成功,幾個堆棧幀之后,您嘗試在方法bar(Lock lock)獲取另一個鎖。

  • 如果您的兩個方法的使用while (true) ,直到他們終於設法獲取鎖,你可以很容易地進入一個僵局,如果一個線程獲得了Afoo()另一種已獲得Bfoo()現在無論是紡紗無休止地在bar() ,試圖獲取彼此的鎖。
  • 如果你只在foo()方法中循環並在獲取鎖不成功時從bar()返回,你可能能夠避免死鎖,但現在:
    • foo()bar()緊密耦合
    • 取決於調用bar()確切時間,獲取第一個鎖和獲取第二個鎖之間的漏洞窗口可能非常大
    • 您需要從foo()的循環開始重新計算整個分支
    • 目標代碼路徑變得非常難以遵循且易於破壞
  • 如果您使用定時鎖,您仍然會遇到上述一些問題,您需要處理InterruptedException ,您需要決定如何循環。
    • 通用技術已經很容易產生一些IllegalMonitorStateException ,這不是太好

如果您定期獲取相同的鎖子集並使用相同的資源子集,您可能需要考慮鎖粗化(將幾個鎖合並為一個)或重新定義您的資源保護策略,以便您不不需要在單個工作流中獲得多級鎖。

PS 經過幾次嘗試,我得到了tryLock()和定時tryLock(long time, TimeUnit unit)方法來處理上述兩種方法,雙鎖方案。 不漂亮,我可以很容易地看到受保護部分中的簡單更改將如何破壞整個方案或使其過於復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM