我正在尝试使用两个线程创建一个简单的“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();
}
}
答案 0 :(得分:2)
从代码中删除ping.join,它将起作用。 ping.join使主线程在ping实例上等待,因此你有2个线程在ping上等待。这就是为什么它只适用于notifyAll。
实际上不需要连接,Java将等待Ping和Pong终止
如果您使用单独的锁进行同步,则不存在此类问题。在线程上同步(Ping是一个线程)是一个坏主意
线程协调不可靠,它取决于线程调度程序。此
notify();
wait();
可能是个问题。想象一下你发送notify()并且当前线程正在移动到wait()时另一个线程唤醒它的工作并发送notify(),如果当前线程没有达到wait()但通知将丢失。您可以轻松模拟此方案,以确定它是真的。