亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

notify()如何按順序或隨機喚醒線程

notify()如何按順序或隨機喚醒線程

DIEA 2021-05-09 16:29:18
我知道notify會喚醒隨機設置在等待中的線程。但是看下面的代碼public class ThreadTest {    public static void main(String[] args) {        Object co = new Object();        System.out.println(co);        for (int i = 0; i < 1000; i++) {            MyThread t = new MyThread("Thread" + i, co);            t.start();        }        try {            TimeUnit.SECONDS.sleep(2);            System.out.println("-----Main Thread notify-----");                synchronized (co) {                    co.notify();                }            TimeUnit.SECONDS.sleep(2);            System.out.println("Main Thread is end.");        } catch (InterruptedException e) {            e.printStackTrace();        }    }    static class MyThread extends Thread {        private String name;        private Object co;        public MyThread(String name, Object o) {            this.name = name;            this.co = o;        }        @Override        public void run() {            try {                synchronized (co) {                    System.out.println(name + " is waiting.");                    co.wait();                    System.out.println(name + " has been notified.");                    co.notify();                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}但是線程按順序喚醒,稱為wait()。這意味著有人wait()先打來電話,然后先醒來。有人wait()第二次叫,第二次弱了...我認為這是我的代碼導致的錯誤,但我不知道問題出在哪里。為了方便顯示,我將迭代次數從20次更改為1000次,但結果相同。
查看完整描述

1 回答

?
慕的地8271018

TA貢獻1796條經驗 獲得超4個贊

規格notify()說:

如果有任何線程在此對象上等待,則選擇其中一個喚醒。該選擇是任意的,并且可以根據實現情況進行選擇。

這意味著您不能期望任何特定的順序,而實現可能會使用它想要的任何特定的順序,包括調用的順序wait。

沒有理由為什么實現應該實現改組。那只會浪費資源。使實現具有自由的原因是允許他們在適合時使用更高效的算法,而不必維護命令。

因此,由于存儲結構不同,不同的實現可能會以相反的順序喚醒它們。如果實現切換到閾值以上的其他存儲結構,則它也可能隨著一定數量的排隊線程而改變。

除此之外,您的測試代碼非常特別。您的主線程在調用之前會等待很長時間notify(),因此所有線程可能已經進入等待狀態,并存儲在JVM使用的任何數據結構中。然后,一次只有一個掛起notify(),因為讓喚醒的線程進行下一個掛起notify()。如果您允許操作重疊,則圖片可能會發生巨大變化。

然后,可能會發現底層數據結構不是純FIFO。同樣,對于實現來說,wait()如果有待處理的線程允許線程調用立即繼續進行notify(),而不考慮等待隊列,而繞過所有已排隊的線程,這是一種安靜的做法,因為這樣做效率更高。

另一點是,如果有多個掛起notify(),則喚醒的線程必須競爭重新獲取對象監視器。這取決于操作系統的調度程序和實際的系統負載,哪個線程將在此處成功執行,因此,即使按入隊的順序喚醒了這些線程,由于JVM無法控制的詳細信息,線程仍可能在此位置被超越。

另外,請不要忘記規范允許虛假喚醒。因此,一個不能夠單獨喚醒單個線程的JVM可以在notify()不違反規范的情況下,由于一次調用而喚醒多個線程。


查看完整回答
反對 回復 2021-05-19
  • 1 回答
  • 0 關注
  • 298 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號