繁体   English   中英

意外的线程唤醒

[英]Unexpected thread wakeup

我期待以下示例中的第二个线程挂起,因为它等待没有相应通知的对象。 相反,它落到了println,可能是由于虚假的唤醒。

public class Spurious {
    public static void main(String[] args) {

        Thread t1 = new Thread() { 
            public void run() { 
                System.out.println("Hey!"); 
            }  
        };
        Thread t2 = new Thread() { 
            public void run() 
            {
                try {
                    synchronized (t1) {
                        t1.wait();
                    }
                } catch (InterruptedException e) {
                    return;
                }
                System.out.println("Done.");
            }
        };
        t1.start();
        t2.start();
    }
}

输出:

Hey!
Done.

另一方面,如果删除“嘿!” println从第一个线程开始,第二个线程确实会挂起。 这种情况发生在MacOS和Linux上。

知道为什么吗?

这不是一个虚假的唤醒,一个虚假的唤醒是由JVM中的竞争条件引起的。 这是您的代码中的竞争条件。

println使thread1保持忙碌的时间足够长,以至于thread2可以在thread1终止之前开始等待。 一旦thread1终止,它就会向其监视器上等待的所有内容发送通知。 thread2收到通知并停止等待。

删除println会减少thread1显着完成所需的时间,以便在thread2开始等待它时,thread1已经完成。 thread1不再处于活动状态,并且在thread2开始等待之前已经发生了通知,因此thread2将永远等待。

Thread for join的API中记录了线程在死亡时发送通知:

此实现使用this.wait调用this.isAlive的循环。 当一个线程终止时,将调用this.notifyAll方法。 建议应用程序不要在Thread实例上使用wait,notify或notifyAll。

道德(嗯,道德之一)总是在一个带有条件变量的循环中等待,参见Oracle教程 如果您将Thread2更改为如下所示:

    Thread t2 = new Thread() { 
        public void run() 
        {
            try {
                synchronized (t1) {
                    while (t1.isAlive()) {
                        t1.wait();
                    }
                }
            } catch (InterruptedException e) {
                return;
            }
            System.out.println("Done.");
        }
    };

然后thread2应该退出,无论thread2是否可以在thread1完成之前开始等待。

当然这是一个完整的玩具示例区域:

  • 不要扩展Thread。

  • 不要锁定线程。

  • 不要启动线程,使用Executors。

  • 更喜欢更高级别的并发结构来等待/通知。

你正在等待一个Thread对象。 这是不好的做法,在Thread的线程(Thread.join)中明确地不鼓励这种做法。

原因是当你调用thread.join()来阻塞直到线程停止运行时,你实际上在等待线程。 当线程停止运行时,它会通知以取消阻止join()所有调用者。

由于您在线程上等待,因此在线程停止运行时会隐式通知您。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM