NotifyAll无法正常工作:程序控制线程执行顺序 - 按顺序打印整数

时间:2016-03-25 14:52:14

标签: java multithreading synchronization

首先,这不是作业。 我写了一段代码,以便:

Thread-1打印1,4,7,...(diff为3)

Thread-2打印2,5,8,...

Thread-3打印3,6,9,......

最终输出应为:

1,2,3,4,5,6,7,8,9,...

这里的代码效果非常好:

package threadAlgo;

public class ControlOrder {
    volatile Monitor monitor = new Monitor();

    public static void main(String[] args) {
        ControlOrder order = new ControlOrder();

        Thread one = new Thread(new Task(order.monitor, 1));
        one.setName("Thread-1");
        Thread two = new Thread(new Task(order.monitor, 2));
        two.setName("Thread-2");
        Thread three = new Thread(new Task(order.monitor, 3));
        three.setName("Thread-3");

        one.start();
        two.start();
        three.start();
    }
}

class Monitor {
    int threadNumber = 1;
}

class Task implements Runnable {

    private Monitor monitor;
    private int myThreadNumber;
    private int currentCount;

    Task(Monitor monitor, int myThreadNumber) {
        this.monitor = monitor;
        this.myThreadNumber = myThreadNumber;
        this.currentCount = myThreadNumber;
    }

    @Override
    public void run() {
        while (true) {
            while (monitor.threadNumber != myThreadNumber) {
                synchronized (monitor) {
                    try {
                        monitor.wait(100); //DOESN'T WORK WITHOUT THE TIMEOUT!!!
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

            synchronized (monitor) {
                if (monitor.threadNumber == myThreadNumber) {
                    System.out.println(Thread.currentThread().getName() + ": " + currentCount);
                    currentCount = currentCount + 3;
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (myThreadNumber == 3) {
                    monitor.threadNumber = 1;
                } else {
                    monitor.threadNumber = myThreadNumber + 1;
                }
                monitor.notifyAll();
            }

        }
    }
}

唯一的问题是如果我使用wait()而不是wait(timeout),那么线程就会停止。

更新

等待条件(while循环)应该在synchronized块内。适合初学者的一课,包括我。

1 个答案:

答案 0 :(得分:2)

你应该总是

  • 结合状态变化执行notifyAll / notify。
  • 在循环中使用wait()之前检查状态更改。

如果你调用notify()并且没有wait()等待,那么信号就会丢失,所以除非你检查一个状态改变,(或超时)你可以永远阻止等待一个不会改变的信号