notify()如何按顺序或随机唤醒线程

时间:2018-07-08 10:34:11

标签: java multithreading jvm thread-safety notify

我知道notify会唤醒随机处于等待状态的线程。但是看下面的代码

public class ThreadTest {
    public static void main(String[] args) {
        Object co = new Object();
        System.out.println(co);

        for (int i = 0; i < 1000; i++) {
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        }

        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("-----Main Thread notify-----");

                synchronized (co) {
                    co.notify();
                }

            TimeUnit.SECONDS.sleep(2);
            System.out.println("Main Thread is end.");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class MyThread extends Thread {
        private String name;
        private Object co;

        public MyThread(String name, Object o) {
            this.name = name;
            this.co = o;
        }

        @Override
        public void run() {
            try {
                synchronized (co) {
                    System.out.println(name + " is waiting.");
                    co.wait();
                    System.out.println(name + " has been notified.");
                    co.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

,但是线程被依次唤醒,名为wait()的线程。这意味着有人先打wait(),然后先叫醒。有人第二次叫wait(),第二次弱了...

我认为这是我的代码导致的错误,但是我不知道问题出在哪里。

为了方便显示,我将迭代次数从20次更改为1000次,但结果相同。

code.thread.ThreadTest
java.lang.Object@45ee12a7
Thread0 is waiting.
Thread1 is waiting.
Thread2 is waiting.
Thread3 is waiting.
Thread4 is waiting.
Thread5 is waiting.
Thread6 is waiting.
Thread7 is waiting.
Thread9 is waiting.
Thread10 is waiting.
Thread11 is waiting.
Thread8 is waiting.
Thread12 is waiting.
Thread13 is waiting.
Thread14 is waiting.
Thread15 is waiting.
Thread16 is waiting.
Thread17 is waiting.
Thread18 is waiting.
Thread19 is waiting.
-----Main Thread notify-----
Thread0 has been notified.
Thread1 has been notified.
Thread2 has been notified.
Thread3 has been notified.
Thread4 has been notified.
Thread5 has been notified.
Thread6 has been notified.
Thread7 has been notified.
Thread9 has been notified.
Thread10 has been notified.
Thread11 has been notified.
Thread8 has been notified.
Thread12 has been notified.
Thread13 has been notified.
Thread14 has been notified.
Thread15 has been notified.
Thread16 has been notified.
Thread17 has been notified.
Thread18 has been notified.
Thread19 has been notified.
Main Thread is end.

Process finished with exit code 0

1 个答案:

答案 0 :(得分:2)

The specification of notify()说:

  

如果有任何线程在等待该对象,则选择其中一个唤醒。选择是任意的,并且可以根据实现情况进行选择。

这意味着您不能期望任何特定顺序,而实现可能会使用它想要的任何特定顺序,包括称为wait的线程的顺序。

没有理由为什么实现应该实现改组。那只会浪费资源。使实现具有自由的原因是允许他们在适合时使用更高效的算法,而不必维护命令。

因此,由于存储结构不同,不同的实现可能以相反的顺序唤醒它们。如果实现切换到阈值以上的其他存储结构,则它也可能随着一定数量的排队线程而改变。

此外,您的测试代码非常特殊。您的主线程在调用notify()之前会等待很长时间,因此所有线程很可能已经进入等待状态,并存储在JVM使用的任何数据结构中。然后,一次只有一个挂起的notify(),因为您让唤醒的线程执行下一个notify()。如果您允许操作重叠,则图片可能会发生巨大变化。

然后,可能会发现底层数据结构不是纯FIFO。此外,对于实现来说,通常允许在有待处理的wait()的情况下允许调用notify()的线程立即继续进行,而无需考虑等待队列,绕过所有已排队的线程,因为这效率更高。< / p>

另一点是,如果有多个挂起的notify(),则已唤醒的线程必须竞争重新获取对象监视器。这取决于操作系统的调度程序和实际的系统负载,哪个线程将在此处成功执行,因此,即使线程按其入队的顺序被唤醒,由于JVM无法控制的细节,线程也可能在此位置被超载。 >

此外,请不要忘记规范允许虚假唤醒。因此,一个不能够单独唤醒单个线程的JVM可以通过一次notify()调用来唤醒多个线程,而不会违反规范。