Код работает с notifyAll, но не с notify

Я пытаюсь создать простую программу "Ping-Pong" с двумя потоками (поток Pong печатает его сообщение только после потока Ping).

Вопрос в том, почему следующий код застревает все время, но прекрасно работает с notifyAll?

Вот мой код:

public class Main {
private static class Ping extends Thread {
    private int rounds;
    Ping(int rounds) { this.rounds = rounds; }
    @Override
    public void run() {
        try {
            synchronized(this) {
                while(rounds > 0) {
                    System.out.println("Ping");
                    notify();
                    wait();
                    --rounds;
                }
                notify();
            }
            System.out.println("Ping done");
        } catch(Exception ignored) { ignored.printStackTrace(); }
    }

    public boolean isDone() { return rounds <= 0; }
}

private static class Pong extends Thread {
    private final Ping ping;
    Pong(Ping ping) { this.ping = ping; }
    @Override
    public void run() {
        try {
            synchronized(ping) {
                while(!ping.isDone()) {
                    System.out.println("Pong");
                    ping.notify();
                    ping.wait();
                }
            }
            System.out.println("Pong done");
        } catch(Exception ignored) { ignored.printStackTrace(); }
    }
}

public static void main(String[] args) throws Exception {
    Ping ping = new Ping(15);
    Pong pong = new Pong(ping);

    ping.start();
    pong.start();

    ping.join();
    pong.join();
}
}

1 ответ

Решение

Удалите ping.join из кода, и он будет работать. ping.join заставляет основной поток ждать на экземпляре ping, поэтому у вас есть 2 потока, ожидающие на ping. Вот почему он работает только с notifyAll.

На самом деле объединения не нужны, Java все равно будет ждать завершения Ping и Pong

Если бы вы использовали отдельную блокировку для синхронизации, не было бы такой проблемы. Синхронизация в потоке (Ping - поток) была плохой идеей

Координация потоков ненадежна, это зависит от планировщика потоков. это

notify();
wait();

может быть проблемой. Представьте, что вы отправляете notify(), и пока текущий поток переходит в ожидание (), другой поток просыпается, выполняет свою работу и также отправляет notify(), если текущий поток не достиг wait(), но уведомление будет потеряно. Вы можете легко подражать этому сценарию, чтобы увидеть, что это правда.

Другие вопросы по тегам