2015-05-17 38 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; 
    } 
}