Java 如何让随机线程等待,然后在固定时间后将其唤醒

Java 如何让随机线程等待,然后在固定时间后将其唤醒,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,在我的主线程中,我创建并启动了四个线程(A、B、C、D),它们每隔500到1000毫秒在控制台上打印字母和数字。 例如A1、A2、A3等 假设主线程每100ms暂停一次随机字母线程,然后将其唤醒。2秒钟后,它会把他们全部杀死 我的问题是,我不能暂停随机字母线程,然后将其唤醒,因为我得到:IllegalMonitorStateException 我的主线程类: public class Main extends Thread { private boolean alive; pri

在我的主线程中,我创建并启动了四个线程(
A、B、C、D
),它们每隔500到1000毫秒在控制台上打印字母和数字。 例如
A1、A2、A3等

假设主线程每100ms暂停一次随机
字母
线程,然后将其唤醒。2秒钟后,它会把他们全部杀死

我的问题是,我不能暂停随机
字母
线程,然后将其唤醒,因为我得到:
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;
    }

}
停止任务

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
    }
}

您的代码示例不起作用,因为wait()调用是在不拥有对象的监视器的情况下进行的

以下是javadoc的解释:

以下是javadoc中的一个片段:

公共最终无效等待() 抛出中断异常

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。换句话说,此方法的行为完全类似于它只执行调用等待(0)。 当前线程必须拥有此对象的监视器。线程释放此监视器的所有权并等待,直到另一个线程通过调用notify方法或notifyAll方法通知等待此对象监视器的线程唤醒。然后线程等待,直到它可以重新获得监视器的所有权并恢复执行

与单参数版本一样,中断和虚假唤醒是可能的,并且此方法应始终在循环中使用:

synchronized(obj){
而()
obj.wait();
…//执行适合条件的操作
}
此方法只能由作为此对象监视器所有者的线程调用。有关线程成为监视器所有者的方式的描述,请参见notify方法。 抛出: IllegalMonitorStateException-如果当前线程不是对象监视器的所有者。 InterruptedException—如果任何线程在当前线程等待通知之前或期间中断了当前线程。引发此异常时,当前线程的中断状态将被清除

我会重新设计代码,让线程自己等待,而不是让线程从外部等待。例如,使用一些共享对象在线程之间共享状态。 我还将使用调度线程执行器。让生活更轻松:

这是一个典型的生产者-消费者问题,有更好的解决方法。由于我们正在解决手头的问题,您可以执行以下操作

您可以去掉互斥对象并使用
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;
    }
}

您正在
mutex
上同步,并在
toStop
上调用
wait()
。您应该调用
mutex.wait()
instead@NitinDandriyal但是我想暂停
toStop
,直到我调用notify.@nitindadriyal我更新了
Main
中的
run
,线程永远不会结束。我添加了
StopTask
,所以现在,复制的代码将编译并运行。您必须首先了解,要在任何对象上调用wait和notify,您必须首先使用
synchronized
关键字获取该对象的监视器,否则会出现此异常。重新编写代码时要记住这一点。当前,您的
互斥锁只对主线程可见,其余
字母
线程不知道也不关心它,因此在主线程中使用当前代码放置等待和通知没有意义您应该始终在回答中附加重要的代码段,由于链接可能不起作用或可能被删除,因此代码段可以工作。请查看修改后的代码。这些信件从未停止印刷。
 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }
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;
    }
}
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;
    }
}