Po wykonaniu wait (), jak długo wątek czeka, jeśli nie zostanie powiadomiony z innych wątków?

Aug 16 2020

W poniższym przykładzie, ponieważ główny wątek nie jest powiadamiany z wątku podrzędnego, powinien czekać wiecznie. Ale główny wątek jest wykonywany, a wynik poniższego przykładu to:

c
l
total: 19900

Dlaczego główny wątek jest wykonywany?

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

    }
}

Odpowiedzi

10 akuzminykh Aug 16 2020 at 09:58

Odpowiedz ciału pytającego

Sprawdź Thread#join(long):

[...] Gdy wątek się kończy, this.notifyAllwywoływana jest metoda. […]

Zwróć uwagę, że Thread#join()wywołuje tę funkcję with 0, co oznacza na zawsze.

[...] Limit czasu równy 0 oznacza czekanie w nieskończoność.

Więc w twoim przypadku tutaj tpo prostu wywołuje notifyAllpo zakończeniu, co powiadamia główny wątek, który czeka t.


To nieintuicyjne zachowanie jest powodem, dla którego piszą w dokumentacji:

Zaleca się, aby nie korzystać z aplikacji wait, notifylub notifyAllna Threadinstancjach.

Odpowiedz na pytanie-tytuł

Sprawdź Object#wait(lub JLS (17.2.1. Czekaj) ):

Wątek może się obudzić bez powiadomienia, przerwania lub przekroczenia limitu czasu, tak zwanego fałszywego wybudzenia. Chociaż w praktyce zdarza się to rzadko, aplikacje muszą się przed tym bronić, sprawdzając warunek, który powinien spowodować przebudzenie wątku, i kontynuując czekanie, jeśli warunek nie zostanie spełniony.

Dzięki temu wątki w Javie mogą się obudzić w dowolnym momencie. Fałszywe przebudzenie jest mało prawdopodobne, ale może się zdarzyć.