簡體   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