2015-05-17 33 views
2

在我的主線程中,我創建並啓動了四個線程(A,B,C,D),它們每隔500到1000ms在控制檯上打印字母和數字。 例如A1,A2,A3如何使隨機線程等待,然後在恆定時間後喚醒

主線程假設暫停隨機Letter線程每隔100ms然後喚醒它。 2秒後,它假設全部殺死它們。

我的問題是,我不能暫停隨機Letter線程將喚醒它,因爲我得到:IllegalMonitorStateException

我的主線程類:

public class Main extends Thread { 
    private boolean alive; 
    private ArrayList<Letter> letters; 
    private Letter toStop; 
    public static Object mutex; 

    public Main() { 
     letters = new ArrayList<Letter>(); 
     alive = true; 
     mutex = new Object(); 
    } 

     public void run() { 
    try { 
     Timer timer = new Timer(); 
     timer.schedule(new StopTask(timer, this), 2 * 1000); 
     letters.add(new Letter()); 
     letters.add(new Letter()); 
     letters.add(new Letter()); 
     letters.add(new Letter()); 
     for (Letter letter : letters) { 
      new Thread(letter).start(); 
     } 

     while (alive) { 
      synchronized (mutex) { 
       toStop = letters.get((int) (Math.random() * letters.size())); 
       System.out.println(toStop.getLetter() + " spi"); 
       mutex.wait(); 
       Thread.sleep(100); 
       mutex.notify(); 
      } 
     for (Letter letter : letters) { 
      letter.kill(); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

    public void kill() { 
     alive = false; 
    } 

} 

和我Letter類:

class Letter implements Runnable { 
    private static int ID; 
    private char letter; 
    private int counter; 
    private boolean alive; 

    public Letter() { 
     letter = (char) ('A' + ID); 
     alive = true; 
     ID++; 
    } 

    @Override 
    public void run() { 

     try { 
      while (alive) { 
       System.out.println(letter + "" + counter); 
       counter++; 
       Thread.sleep((int) (Math.random() * 501 + 500)); 
      } 
      System.out.println("Watek " + letter + " sie zakonczyl"); 
     } catch (Exception e) { 

     } 

    } 

    public void kill() { 
     alive = false; 
    } 

    public char getLetter() { 
     return letter; 
    } 

} 

StopTask

import java.util.Timer; 
import java.util.TimerTask; 

public class StopTask extends TimerTask { 
    private Timer timer; 
    private Main main; 

    public StopTask(Timer timer, Main main) { 
     this.timer = timer; 
     this.main = main; 
    } 

    public void run() { 
     System.out.println("Time's up!"); 
     main.kill(); 
     timer.cancel(); //Not necessary because we call System.exit 
    } 
} 
+1

您正在同步'mutex'並在'toStop'上調用'wait()'。你應該調用'mutex.wait()'而不是 –

+0

@NitinDandriyal,但我想暫停'toStop'直到我調用notify。 – Yoda

+0

@NitinDandriyal我更新'Main'中的'run'線程永遠不會結束。我現在添加了'StopTask',複製的代碼將被編譯並運行。 – Yoda

回答

0

您的代碼示例不起作用,因爲wait()調用沒有擁有對象的監視器。

這裏是javadoc的解釋: https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait()

下面是從javadoc的片段:

公衆最終無效的wait() 拋出InterruptedException的

造成當前線程等待,直到另一個線程爲此對象調用notify()方法或notifyAll()方法。換句話說,這個方法的行爲就好像它只是執行呼叫等待(0)一樣。 當前線程必須擁有該對象的監視器。線程釋放此監視器的所有權,並等待另一個線程通知對通知方法或notifyAll方法的調用,以便通知通過此對象監視器等待的線程喚醒。該線程然後等待,直到它可以重新獲得監視器的所有權並恢復執行。

正如一個參數的版本,中斷和虛假喚醒是可能的,而且此方法應始終在循環中使用:

synchronized (obj) { 
    while (<condition does not hold>) 
     obj.wait(); 
    ... // Perform action appropriate to condition 
} 

此方法應該僅由一個線程調用該是此對象監視器的所有者。有關線程可以成爲監視器所有者的方式的說明,請參閱notify方法。 拋出: IllegalMonitorStateException - 如果當前線程不是對象監視器的所有者。 InterruptedException - 如果在當前線程正在等待通知之前或當前任何線程中斷當前線程。拋出此異常時,當前線程的中斷狀態將被清除。

我會重新設計代碼,讓線程自己等待,而不是被告知要從外面等待。例如,使用一些共享對象來共享線程間的狀態。 我也會使用預定的線程執行程序。使生活更輕鬆: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

+0

你應該總是在你的答案中附加重要的代碼片段,因爲鏈接可能不工作或可能被刪除,因此片段工作 –

+0

請看看修改後的代碼。字母不會停止印刷。 – Yoda

0

這是一個典型的生產者 - 消費者問題,並有更好的方法來做到這一點。既然我們正在解決手頭的問題,你可以在下面做。

可以擺脫互斥對象,並使用Letter實例作爲互斥體,所以有效地你有4個互斥的各統籌與Main

public class Main extends Thread{ 
    private boolean alive; 
    private ArrayList<Letter> letters; 
    private Letter toStop; 
    //public static Object mutex; 

    public Main() { 
     letters = new ArrayList<Letter>(); 
     alive = true; 
     mutex = new Object(); 
    } 

    public void run() { 
     try { 
      Timer timer = new Timer(); 
      timer.schedule(new StopTask(timer, this), 2 * 1000); 
      letters.add(new Letter()); 
      letters.add(new Letter()); 
      letters.add(new Letter()); 
      letters.add(new Letter()); 

      for (Letter letter : letters) { 
       new Thread(letter).start(); 
      } 

      while (alive) { 
       // synchronized (mutex) { 
       toStop = letters.get((int) (Math.random() * letters.size())); 
       synchronized (toStop) { 
        //System.out.println(toStop.getLetter() + " spi"); 
        // mutex.wait(); 
        //Thread.sleep(100); 
        // mutex.notify(); 
        toStop.setToGetLetter(true); 
        toStop.notify(); 
       } 
       System.out.println(toStop.getLetter() + " spi"); 
       Thread.sleep(100); 
      } 
      // } 
      for (Letter letter : letters) { 
       letter.kill(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 

    public void kill() { 
     alive = false; 
    } 
} 

而在你Letter線程,你可以使用this合作與主服務器配合使用

public class Letter implements Runnable { 
    private static int ID; 
    private char letter; 
    private int counter; 
    private boolean alive; 
    private volatile boolean toGetLetter = false; 

    public boolean isToGetLetter() { 
     return toGetLetter; 
    } 

    public void setToGetLetter(boolean toGetLetter) { 
     this.toGetLetter = toGetLetter; 
    } 

    public Letter() { 
     letter = (char) ('A' + ID); 
     alive = true; 
     ID++; 
    } 

    @Override 
    public void run() { 

     try { 
      while (alive) { 
       synchronized (this) { 
        while (!isToGetLetter()) { 
         this.wait(); 
       } 
       System.out.println(letter + "" + counter); 
       counter++; 
       Thread.sleep((int) (Math.random() * 501 + 500)); 
       toGetLetter = false; 
       this.notify(); 
      } 
     } 
     System.out.println("Watek " + letter + " sie zakonczyl"); 
    } catch (Exception e) { 

    } 
} 

    public void kill() { 
     alive = false; 
    } 

    public char getLetter() { 
     return letter; 
    } 
}