2014-03-02 109 views
3

我有一個很難理解ReentrantLock.lock()ReentrantLock.lock()不會阻止其他線程

我有下面的類行爲

import java.util.concurrent.locks.*; 

class BlockingClass { 

    private Lock lock = new ReentrantLock(); 

    private Condition condition = lock.newCondition(); 

    public void a() { 
     lock.lock(); 
     System.out.println("called in method a(): lock()"); 

     try { 
      System.out.println("called in method a(): await()"); 
      condition.await(); 
     } 
     catch (InterruptedException e) {} 
     finally { 
      lock.unlock(); 
      System.out.println("called in method a(): unlock() "); 
     } 
    } 

    public void b() { 
     lock.lock(); 
     System.out.println("called in method b(): lock()"); 

     System.out.println("called in method b(): signalAll()"); 
     condition.signalAll(); 

     lock.unlock(); 
     System.out.println("called in method b(): unlock() "); 
    } 
} 

我與運行以下測試:

class BlockingClassTest { 
    public static void main(String[] args) throws InterruptedException { 

     final BlockingClass blockingClass = new BlockingClass(); 

     new Thread() { 
      public void run() { 
       System.out.println("Thread1 calling a()"); 
       blockingClass.a(); 
      } 
     }.start(); 

     Thread.sleep(1000); 

     new Thread() { 
      public void run() { 
       System.out.println("Thread2 calling b()"); 
       blockingClass.b(); 
      } 
     }.start(); 
    } 
} 

我本來預計會出現死鎖。一旦a()方法調用lock.lock(),我期望任何調用b()方法的人都必須在b的lock.lock()處等待,直到調用a()的線程調用lock.unlock()。但是由於a()正在等待b()調用condition.signalAll(),所以這兩種方法都應該永遠保持阻塞狀態。

相反,這是我的輸出在控制檯中看到:

Thread1 calling a() 
called in method a(): lock() 
called in method a(): await() 
Thread2 calling b() 
called in method b(): lock() 
called in method b(): signalAll() 
called in method a(): unlock() 
called in method b(): unlock() 

什麼我誤解有關正確使用和鎖定功能()和unlock()?

回答

5

你不會誤解ReentrantLock,你誤會了Condition。一個Condition綁定到一個鎖,Condition.await()將有效解鎖,檢查並等待,然後重新鎖定鎖。見Condition.await()

a()lock()和調用await(),並await()unlock()回報之間,因爲你希望你的鎖定行爲。在致電await()的電話中,Condition正在管理它。

這是「條件變量」一般概念的一部分;這就是爲什麼你找到的任何線程庫都會將某種類型的鎖與條件關聯起來(例如,在POSIX C中,pthread_cond_wait需要條件變量互斥體)。

查看關於condition variables的維基百科文章,它詳細解釋了此行爲及其原因。

+0

謝謝,@ortang和傑森C爲您的偉大和快速的答案。我僅僅因爲它的完整性和有用的文檔而接受這個。 – Student

2

您致電condition.await();將釋放鎖,使線程處於wait狀態,以便線程b可以獲取該鎖。

您的a()方法將繼續運行一次b()已釋放它的鎖定,因爲您已發送條件。

+0

你如何解釋'a()unlock()'發生在'b()unlock()'之前的事實? –

+2

這是您的代碼中的競爭條件。 System.out.println(「...」);方法被同時調用,因爲不再獲取鎖。 –

+0

^您可以在'unlock()'調用之前放置一個打印輸出,以查看更準確的操作順序視圖,@SotiriosDelimanolis –

1

答案已經給出,但我想我剛引述javadocs for Condition.await()提供更多的背景:

造成當前線程在等待,直到它發出信號或中斷。

與此條件相關的鎖原子方式釋放,和當前線程用於線程調度目的,禁用並一直處於休眠狀態的以下四種情況之一發生:

  1. 其他某些線程調用信號方法此條件和當前線程碰巧被選爲要被喚醒的線程;或
  2. 其他一些線程調用此條件的signalAll方法;或
  3. 某些其他線程中斷當前線程,並支持中斷線程掛起;或
  4. 發生「虛假喚醒」。

在所有情況下,在此方法可以返回之前,當前線程必須重新獲取與此條件相關的鎖。當線程返回時,它保證保持這個鎖。

因此,當您撥打condition.await()時,它會釋放允許其他線程進入鎖定部分的鎖定。這與​​代碼塊內部的Object.wait()的行爲相同。

+0

感謝您參考Object.wait()。這也很有幫助。 – Student

相關問題