2015-02-10 91 views
1

我想了解線程如何在Java中工作。因此,我寫了一小段代碼,我創建了兩個線程,一個打印所有奇數和其他打印偶數,並嘗試在它們之間進行同步,以便所有數字都按順序打印。爲什麼我的代碼拋出IllegalMonitorStateException?

public class Main 
{ 

    public static void main (String args[]){ 

     Main lock = new Main(); 

     Test t1 = new Test(1, lock); 

     Test t2 = new Test(2, lock); 

     synchronized(lock){ 

      (new Thread(t1)).start(); 
      (new Thread(t2)).start(); 

     } 


    } 

} 

public class Test implements Runnable { 


    int n; 
    Main lock; 

    public Test(int newN, Main lockObj){ 
     this.n = newN; 
     this.lock = lockObj; 
    } 


    public void run() { 


     while(true){ 

      if (n != 1){ 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 

        e.printStackTrace(); 
       } 
      } 

      n = n + 2; 

      System.out.println(n); 

      lock.notify(); 

     } 


    } 


} 

可有人請幫助理解潛在的問題是什麼?

+0

將'Main'的實例用作鎖對象有點奇怪。它沒有傷害,但更傳統的說'對象鎖定=新對象()'。當你開始與其他開發人員合作時,更傳統就變得很重要。如果你的代碼看起來不奇怪,他們會更樂意與你一起工作。 – 2015-02-10 18:13:17

+0

重要的是要注意,wait()必須始終在嚴格循環內調用,以檢查正在等待的條件。該方法的[文檔](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--)具有完整的詳細信息和示例。 – VGR 2015-02-10 19:25:24

回答

6

您有三個線程,main線程,t1t2。線程擁有鎖可以使用動作notify,notifyAllwait。在這種情況下main線程擁有的鎖不是t1t2

您需要在每個線程的run方法內同步以便能夠wait


下面是我通過synchronizingrun方法意味着一個例子。

在啓動線程後,從run方法發生的任何操作都將由該線程運行完成。所以,當你嘗試和wait你會想要確保線程擁有鎖,你可以通過在run方法中同步它來做到這一點。

public void run() { 
    synchronized(lock){ 
     while(true){ 
      if (n != 1){ 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      n = n + 2; 
      System.out.println(n); 
      lock.notify(); 
     } 
    } 
} 

正如你可以看到我的run方法中的同步,這樣t1t2自己鎖在通知或等待。

+0

我嘗試從'main'線程中移除鎖並在Test中創建一個靜態鎖(Main類),但得到了相同的結果。 考慮到班級結構,我如何才能解決特定問題的任何想法都保持不變? – user2560730 2015-02-10 17:55:31

+1

正如我最後一句話所說。你必須在每個獨立線程的run方法中同步。不在'main'方法中。 – 2015-02-10 18:13:08

+0

不確定你的意思是「主線擁有鎖」。這是一種可能性,但由於主線程與另外兩個線程不同步,並且由於它只在短時間內擁有鎖定,所以主線程已經很可能已經釋放了鎖並在任何一個之前終止兩個線程輸入Test#run()方法。 – 2015-02-10 18:20:51

0

這可能不會幫助您理解低級別的線程機制,但對於您的情況,使用CyclicBarrier與barrierAction是有意義的。

使兩個踏板等待障礙處理後n = n + 2,讓barrierAction sysout雙線程當前的n,重複。

相關問題