how the notify() wake up thread in order or at random

问题: I know notify will wake up the thread which is in wait set at random. But look at the following code public class ThreadTest { public static void main(String[] args)...

问题:

I know notify will wake up the thread which is in wait set at random. But look at the following code

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();
            }
        }
    }

}

but the threads wake up in order as the thread called wait(). It means someone call wait() first, it wakes up first; someone call wait() second, it weak up second...

I think it is the error from my code results in this, but I don't know where is the problem.

For convenience to show it, I change the iteration from 20 times, but when it is 1000 times, the result is the same.

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:

The specification of notify() says:

If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation.

This implies that you can not expect any particular order while the implementation may use any particular order it wants, including the order in which threads called wait.

There is no reason why an implementation should implement shuffling. That would only waste resources. The reason to give implementations that freedom is to allow them to use more efficient algorithms whenever they fit, without having to maintain an order.

So it may happen that a different implementation wakes them up in opposite order due to a different storage structure. It could also change with a certain number of enqueued threads if the implementation switches to a different storage structure above a threshold.

Besides that, your test code is very special. Your main thread waits quiet a long time before calling notify(), so it is likely that all threads have already entered the wait state and are stored in whatever data structure the JVM uses. Then, you have only one pending notify() at a time, as you let the thread which has been woken up do the next notify(). The picture may change dramatically if you allow the operations to overlap.

Then, it may turn out that the underlying data structure is not a pure FIFO. Also, it is quiet common for implementations to allow a thread calling wait() to proceed immediately if there is a pending notify(), without considering the waiting queue, bypassing all already enqueued threads, because that’s more efficient.

Another point is that if there is more than one pending notify(), the threads which have been woken up have to compete for reacquiring the object monitor. It depends on the operating system’s scheduler and the actual system load, which thread will succeed here, so even if the threads were woken up in the order they were enqueued, threads could overtake at this place due to details outside the JVM’s control.

Also, don’t forget that the specification allows spurious wakeup. So A JVM not capable of waking up a single thread individually could wake up more than one thread due to a single notify() call without violating the specification.

  • 发表于 2018-07-10 01:51
  • 阅读 ( 168 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除