2013-01-23 35 views
4

我看不到以下代碼如何產生看起來違反對象鎖的定義的輸出。當然,只有一個線程應該被允許打印「獲得的鎖定」消息,但它們都是?使用內部鎖進行塊輸入

class InterruptThreadGroup { 
    public static void main(String[] args) { 
     Object lock = new Object(); 
     MyThread mt1 = new MyThread(lock); 
     MyThread mt2 = new MyThread(lock); 
     mt1.setName("A"); 
     mt1.start(); 
     mt2.setName("B"); 
     mt2.start(); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
     } 
     // Thread.currentThread().getThreadGroup().interrupt(); 
    } 
} 

class MyThread extends Thread { 
    private Object lock; 

    public MyThread(Object l) { 
     this.lock = l; 

    } 

    public void run() { 
     synchronized (lock) { 
      System.out.println(getName() + " acquired lock"); 
      try { 
       lock.wait(); 
      } catch (InterruptedException e) { 
       System.out.println(getName() + " interrupted."); 
      } 
      System.out.println(getName() + " terminating."); 
     } 
    } 
} 
+0

不是一個好主意來擴展線程類。你應該實現可運行的接口。 – Arpit

回答

7

這是因爲調用lock.wait()會釋放鎖,從而允許第二個線程進入同步塊。從javadoc

提取這款顯示器並等待線程釋放所有權,直到另一個線程通知等候在這個對象監視器上或者通過notify方法或notifyAll方法的調用醒來。該線程然後等待,直到它可以重新獲得監視器的所有權並恢復執行。

需要注意的是有你的代碼的一些問題,如:

  • 你不應該等待一段時間循環外
  • 沒有通知任何地方,所以你的等待會天長地久
  • 最好讓您的任務實現Runnable並將其作爲參數傳遞給Thread的構造函數,而不是直接擴展Thread。
+1

+1我會補充說OP正在鎖定一個非最終字段,並且沒有正在檢查的狀態來確定是否需要wait()或虛假地喚醒。 –

0

要麼你應該使用同步塊或等待呼叫。一起使用它們是行不通的。如果您使用等待調用,則鎖定由同步塊中的對象釋放。

因此,刪除行lock.wait,你的程序將按你的意願工作。同步塊將自動處理所有鎖定。

如果您使用等待,則必須使用通知。

以下是有關這個好螺紋:Why must wait() always be in synchronized block