该代码适用于notifyAll,但不适用于notify

时间:2013-03-31 05:10:59

标签: java multithreading concurrency wait 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 个答案:

答案 0 :(得分:2)

从代码中删除ping.join,它将起作用。 ping.join使主线程在ping实例上等待,因此你有2个线程在ping上等待。这就是为什么它只适用于notifyAll。

实际上不需要连接,Java将等待Ping和Pong终止

如果您使用单独的锁进行同步,则不存在此类问题。在线程上同步(Ping是一个线程)是一个坏主意

线程协调不可靠,它取决于线程调度程序。此

notify();
wait();

可能是个问题。想象一下你发送notify()并且当前线程正在移动到wait()时另一个线程唤醒它的工作并发送notify(),如果当前线程没有达到wait()但通知将丢失。您可以轻松模拟此方案,以确定它是真的。