为什么notifyAll有时无效?

问题描述

我已经创建了这个程序:

public class NotifyTest {
    public synchronized void sendNotify() {
        notifyAll();
    }

    public synchronized void receiveNotifies(int notifies) {
        while (notifies > 0) {
            try {
                wait();
            } catch (InterruptedException e) {}
            notifies--;
            System.out.println(Thread.currentThread().getName() + " left wait(),decremented notifies,current notifies count " + notifies);
        }
    }

    public static void main(String[] args) {
        NotifyTest notifyTest = new Notifytest();
        for (int i = 0; i < 9; i++) {
            Thread t1 = new Thread(() -> {
                notifyTest.receiveNotifies(4);
            });
            t1.setName("receiveNotifiesThread: " + i);
            t1.start();
        }

        System.out.println("Waiting until all receivers are started. Every Thread should be stopped after 4 notifies");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {}

        new Thread(() -> {
            for (int i = 0; i < 4; i++) {
                System.out.println("Sent notify " + i);
                notifyTest.sendNotify();
                try {
                    Thread.sleep((int) Math.random());
                } catch (Exception e) {}
            }
        }).start();
    }
}

通常应在4次sendNotify()调用之后停止所有线程。无论如何,当我运行该程序时,有时会挂起,因为receiveNotify()线程错过了接收通知的时间。程序挂起时,输出如下所示:

> Waiting until all receivers are started. Every Thread should be stopped after 4 notifies
> Sent notify 0
> receiveNotifiesThread: 8 left wait(),current notifies count 3
> receiveNotifiesThread: 7 left wait(),current notifies count 3
> receiveNotifiesThread: 6 left wait(),current notifies count 3
> receiveNotifiesThread: 5 left wait(),current notifies count 3
> receiveNotifiesThread: 4 left wait(),current notifies count 3
> receiveNotifiesThread: 3 left wait(),current notifies count 3
> Sent notify 1
> receiveNotifiesThread: 2 left wait(),current notifies count 3
> receiveNotifiesThread: 1 left wait(),current notifies count 3
> receiveNotifiesThread: 0 left wait(),current notifies count 3
> Sent notify 2
> Sent notify 3
> receiveNotifiesThread: 0 left wait(),current notifies count 2
> receiveNotifiesThread: 1 left wait(),current notifies count 2
> receiveNotifiesThread: 2 left wait(),current notifies count 2
> receiveNotifiesThread: 3 left wait(),current notifies count 2
> receiveNotifiesThread: 4 left wait(),current notifies count 2
> receiveNotifiesThread: 5 left wait(),current notifies count 2
> receiveNotifiesThread: 6 left wait(),current notifies count 2
> receiveNotifiesThread: 7 left wait(),current notifies count 2
> receiveNotifiesThread: 8 left wait(),current notifies count 1
> receiveNotifiesThread: 7 left wait(),current notifies count 1
> receiveNotifiesThread: 6 left wait(),current notifies count 1
> receiveNotifiesThread: 5 left wait(),current notifies count 1
> receiveNotifiesThread: 4 left wait(),current notifies count 1
> receiveNotifiesThread: 3 left wait(),current notifies count 1
> receiveNotifiesThread: 2 left wait(),current notifies count 1
> receiveNotifiesThread: 1 left wait(),current notifies count 1
> receiveNotifiesThread: 0 left wait(),current notifies count 1

您知道如何解决吗?

解决方法

发送通知时...

            for (int i = 0; i < 4; i++) {
                System.out.println("Sent notify " + i);
                notifyTest.sendNotify();
                try {
                    Thread.sleep((int) Math.random());
                } catch (Exception e) {}
            }

...让线程休眠(int) Math.random()毫秒。函数Math.random()返回一个介于double0.0之间的1.0。将其强制转换为int即可得到0。因此,让线程休眠0毫秒。

等待线程醒来时将其打印到控制台,这需要时间。如果您的通知程序线程根本没有休眠(0毫秒),并且在前一个通知之后立即发出通知,则等待程序线程无法到达wait调用,因此通知已没有效果。

要解决此问题,只需避免在sleep通话中使用零,例如:

                try {
                    Thread.sleep((int) (Math.random() * 100 + 1));
                } catch (Exception e) {}