Po wykonaniu wait (), jak długo wątek czeka, jeśli nie zostanie powiadomiony z innych wątków?
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
Odpowiedz ciału pytającego
Sprawdź Thread#join(long):
[...] Gdy wątek się kończy,
this.notifyAll
wywoł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 t
po prostu wywołuje notifyAll
po 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
,notify
lubnotifyAll
naThread
instancjach.
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ć.