Как долго после выполнения wait () поток ожидает, если он не получает уведомления от других потоков?

Aug 16 2020

В приведенном ниже примере, поскольку основной поток не получает уведомления от дочернего потока, он должен ждать вечно. Но основной поток выполняется, и результат следующего примера:

c
l
total: 19900

Почему выполняется основной поток?

public class ThreadX extends Thread {
    static int total = 0;

    public void run() {
        synchronized (this) {
            for (int i = 0; i < 200; i++) {
                total = total + i;
            }
            System.out.println("c");

        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadX t = new ThreadX();

        t.start();
        synchronized (t) {
            t.wait();
            System.out.println("l");
        }

        System.out.println("total: " + total);

    }
}

Ответы

10 akuzminykh Aug 16 2020 at 09:58

Ответ на основной вопрос

Проверить Thread#join(long):

[...] Когда поток завершается this.notifyAll, вызывается метод. [...]

Обратите внимание, что Thread#join()эта функция вызывается с помощью 0, что означает навсегда.

[...] Таймаут 0 означает ждать вечно.

Итак, в вашем случае здесь tпросто вызывается, notifyAllкогда он завершается, что уведомляет основной поток, который ожидает t.


Это неинтуитивное поведение является причиной того, что в документации написано следующее:

Рекомендуется , чтобы приложения не используют wait, notifyили notifyAllна Threadслучаях.

Ответ на вопрос-заголовок

Выписка Object#wait(или JLS (17.2.1. Подождите) ):

Поток может проснуться без уведомления, прерывания или тайм-аута, так называемое ложное пробуждение. Хотя на практике это случается редко, приложения должны защищаться от этого, проверяя условие, которое должно было вызвать пробуждение потока, и продолжая ждать, если условие не выполняется.

Таким образом, потоки в Java могут проснуться в любой момент. Ложное пробуждение маловероятно, но может произойти.