2012-07-21 118 views
0
System.out.println("Thread state: " + threads[i].getState()); 
threads[i].notify(); 

產生以下輸出:Java - 無法通知等待線程?

Thread state: WAITING 
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException 
at java.lang.Object.notify(Native Method) 
at MyPakc.An.run(An.java:49) 
at java.lang.Thread.run(Thread.java:679) 

這是怎麼回事?爲什麼我不能通知睡眠線程?

編輯:

package Part2; 

import java.util.List; 
import javax.swing.JPanel; 



class BThread extends Thread{ 
    private boolean completedThisIter = false; 

    @Override 
    public synchronized void run() { 
     while (true) { 
      completedThisIter = false; 
      doStuff() 
      System.out.println("Completed iter"); 
      completedThisIter = true; 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public boolean getCompletedThisIter() { 
     return completedThisIter; 
    } 
} 

編輯:對於線程[]類的代碼下面是調用此

public synchronized void run(){ 
// OTHER STUFF 
    for (int iter = 0; iter < 1212; ++iter){ 
     System.out.println("Iter " + iter); 
     lastAssignedBallIndex = -1; 
     for (int i = 0; i < numThreads; i++) { 
      //System.out.println("Num " + numThreads + " " + i); 
      //ballThreads[i] = new BallThread(ballList.subList(lastAssignedBallIndex+1,lastAssignedBallIndex+numBallsPerThread), 
      //  ballPanel); 
      //lastAssignedBallIndex += numBallsPerThread; 
      System.out.println("State " + ballThreads[i].getState()); 
      if (ballThreads[i].getState() == Thread.State.NEW) { 
       ballThreads[i].start(); 
      } else { //if (ballThreads[i].getState() == Thread.State.BLOCKED) { 
       System.out.println("Thread state: " + ballThreads[i].getState()); 
       ballThreads[i].notify(); 
      } 
     } 
     //try{ 
      for (int i = 0; i < numThreads; i++) { 
       while (!ballThreads[i].getCompletedThisIter()) { 
        System.out.println("iter:" + iter + " ball:" + i + " " + ballThreads[i].getCompletedThisIter()); 
        //wait(); // TODO elliminate polling here 
       } 
      } 
      System.out.println("Joined"); 
     //} 
     // catch(InterruptedException ie){ie.printStackTrace();} 


     ballPanel.repaint(); 
     notifyAll(); 
     try{ 
      Thread.sleep(2); 
     } 
     catch (InterruptedException ie){} 
    } 
} 
+0

你可以顯示正在等待的線程的代碼嗎? – 2012-07-21 04:48:50

+0

你想達到什麼目的?通知'Thread'對象不會導致任何事情發生,除非有另一個線程調用'wait()'。 – SimonC 2012-07-21 04:57:40

+0

是的,我給你的狀態輸出在調用notify()之前,你看到它正在等待 – Trup 2012-07-21 05:01:29

回答

2

代碼你打印出一個ballThreads[i]的狀態,那麼通知一個threads[i]。不確定這是否是預期行爲,但是當您不擁有對象的顯示器時,您不允許通知線程。你確定你在對象的synchronized()塊內調用了這個嗎?


編輯:

是,這段代碼取出的方法是同步的

您的編輯你的問題後,​​是方法,而不是對象的監視器,您需要將代碼放在如下所示的塊中:

synchronized(threads[i]) { 
    // some stuff 
    threads[i].notify(); 
} 

這裏的重要一點(與方法聲明中的​​關鍵字相反)是您在一個對象上同步,然後在該塊內部,您可以調用notify()對象對象。例子:

public void run() 
{ 
    synchronized(myObject) { 
     // do some stuff 
     myObject.notify(); 
    } 
} 

public void run() 
{ 
    synchronized(thread1) { 
     // do some stuff 
     thread1.notify(); 
    } 
} 

public void run() 
{ 
    synchronized(syncObject) { 
     // do some stuff 
     syncObject.notify(); 
    } 
} 

看到這個模式?此處更多信息:http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

+0

看到編輯,你沒有在對象的監視器上同步 – 2012-07-21 05:00:47

+0

@Trup不,你正在同步一個方法,它使用對象實例作爲監視器,而不是你調用notify()對象**你需要同步你調用'notify()'的對象的實例。 – 2012-07-21 05:07:16

+0

@Trup ok,這裏有一堆例子 – 2012-07-21 05:12:43

1

wait()notifiy()要求您在等待的對象上進行同步。如果你用於鎖定同步塊相同的對象上做一個wait()notify(),那麼你將擺脫非法監控狀態異常

1

你是完全誤解wait/notify機制的工作方式的。線程必須決定是否需要等待。然後該線程必須調用wait。然後,有什麼事情發生。然後你撥打notify告訴線索發生了什麼事。

如果沒有首先確定應該等待的具體內容,則不能讓線程調用wait。並且在線程需要被通知的事情已經發生之前,你不能調用notify。發生的事情應該是線程在決定等待時檢查的內容。

您遇到錯誤的原因是與等待的事件關聯的同步根本不存在,這違反了wait/notify的語義。

如果您在等待郵箱非空,則應檢查郵箱是否爲空,如果是,請撥打wait。確保您仍在郵箱的同步例程內,否則您無法知道郵箱(仍然)爲空。然後,當您將信件放入郵箱(必須位於郵箱的同步例程內)時,請致電notify讓任何等待的線程知道郵箱已更改狀態。您必須等待以獲得的線程可以測試的內容,例如郵箱的狀態。