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

Posted

技术标签:

【中文标题】该代码适用于 notifyAll,但不适用于 notify【英文标题】:The code works with notifyAll, but doesn't with notify 【发布时间】:2013-03-31 05:10:58 【问题描述】:

我正在尝试创建一个带有两个线程的简单“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() 并且当当前线程移动到 wait() 时,另一个线程醒来完成它的工作并发送 notify() ,如果当前线程尚未到达 wait() 但通知将丢失。你可以很容易地模拟这个场景,看看它是不是真的。

【讨论】:

非常感谢!没想到主线程也在等待资源:)

以上是关于该代码适用于 notifyAll,但不适用于 notify的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 代码适用于 Windows 但不适用于 Mac

查询适用于 phpMyAdmin,但不适用于 Java [重复]

Angular CORS 适用于 GET 但不适用于 DELETE

我的代码适用于输入文件,但不适用于其他文件。 (调试断言错误)

为啥 mysql 中的这个查询适用于该表,但不适用于该表的视图?

UITabBar 外观适用于 iOS6 但不适用于 iOS 5