Object.wait以及notify注解

wait()

* Causes the calling thread to wait until another thread calls the {@code
     * notify()} or {@code notifyAll()} method of this object. This method can
     * only be invoked by a thread which owns this object's monitor; see
     * {@link #notify()} on how a thread can become the owner of a monitor.
     * <p>
     * A waiting thread can be sent {@code interrupt()} to cause it to
     * prematurely stop waiting, so {@code wait} should be called in a loop to
     * check that the condition that has been waited for has been met before
     * continuing.
     * <p>
     * While the thread waits, it gives up ownership of this object's monitor.
     * When it is notified (or interrupted), it re-acquires the monitor before
     * it starts running.
     * @throws IllegalMonitorStateException
     *             if the thread calling this method is not the owner of this
     *             object's monitor.
     * @throws InterruptedException
     *             if another thread interrupts this thread while it is waiting.

該方法的注釋說:使調用線程處于wait狀態(tài)迁筛,直到其他線程調用這個Object的notify或者notifyAll才會被喚醒榴啸。這個方法只能被擁有這個Object的Monitor才能被調用擦剑。一個正在wait的線程能夠被調用interrupt方法苏潜。
當一個線程處于Wait漱受,它放棄了它自己的Object Monitor瞻凤,當它被notified或者interrupted的時候伶唯,它會在它啟動之前重新請求這個monitor

noitify()

* Causes a thread which is waiting on this object's monitor (by means of
* calling one of the {@code wait()} methods) to be woken up. If more than one thread is waiting, one of them is chosen at the discretion of the VM. The chosen thread will not run immediately. The thread
     * that called {@code notify()} has to release the object's monitor first.
     * Also, the chosen thread still has to compete against other threads that
     * try to synchronize on the same object.
     * This method can only be invoked by a thread which owns this object's
     * monitor. A thread becomes owner of an object's monitor by executing a synchronized method of that object; by executing the body of a {@code synchronized} statement that synchronizes on the object;by executing a synchronized static method if the object is of type {@code Class}.

使得一個正在等待這個Object的Monitor的線程被喚醒觉既。如果超過一個線程正在等待的話,那么就只有一個線程會被喚醒,而這個線程會由VM自己決定瞪讼。而這個被選擇的線程并不會立馬就進入run的狀態(tài)钧椰,調用了notify的線程會首先釋放這個Object的Monitor。并且符欠,被選擇的線程必須完成和其他線程完成對這個Object鎖的競爭嫡霞。這個方法只能被擁有這個Object的Monitor的線程調用。這個線程擁有這個Object的Monitor希柿,通過執(zhí)行一個同步方法或者一個同步的代碼塊來獲取這個對象的鎖诊沪,或者通過執(zhí)行這個對象的Class類來進行同步。

簡單來說曾撤,也就是在使用wait和notify的時候端姚,需要使用synchoronized代碼塊將對象進行Monitor操作,這個操作可以是一個同步代碼塊挤悉,也可以是一個同步的方法渐裸,也可以用一個class對象進行同步,總之装悲,在調用wait和notify的時候橄仆,必須要進行同步。并且在有多個線程處于wait狀態(tài)的時候衅斩,當調用notify的時候,只有一個線程會收到這個消息怠褐,如果是notifyAll的話畏梆,所有的線程都會進行競爭,最后也只會有一個線程能夠獲取到資源奈懒,但是它也不會立馬進行到run的狀態(tài)奠涌,而是進入就緒的狀態(tài),等待時間片到它的時候磷杏,就可以執(zhí)行了溜畅。而這個線程的選擇是靠JVM來自主決定的。

下面舉一個例子:

  1. 錯誤的例子:使用wait和noitify的時候沒有加同步代碼塊

    public class Test {
    public static void main(String[] args) {
          Object lock = new Object();
          ThreadA threadA = new ThreadA(lock);
          ThreadB threadB = new ThreadB(lock);
          threadA.start();
          threadB.start();
    }
    private static class ThreadA extends Thread {
          Object obj;
    
        public ThreadA(Object lock) {
            obj = lock;
            setName("ThreadA");
        }
    
        @Override
        public void run() {
            super.run();
            System.out.println("Start Wait:" + Thread.currentThread().getName());
            try {
                obj.wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
            System.out.println("Wait End:" + Thread.currentThread().getName());
        }
    }
    
    private static class ThreadB extends Thread {
        Object obj;
    
    public ThreadB(Object lock) {
        obj = lock;
        setName("ThreadB");
    }
    
        @Override
        public void run() {
            super.run();
            System.out.println("ThreadB Start:" + Thread.currentThread().getName());
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
            }
            System.out.println("After ThreadB Sleep 5S");
            obj.notify();
            System.out.println("ThreadB notify:" + Thread.currentThread().getName());
            }
        }
     }
    

運行后的結果為:

代碼1運行結果
  1. 正確使用wait notify的例子:

    public class Test {
        public static void main(String[] args) {
            Object lock = new Object();
            ThreadA threadA = new ThreadA(lock);
            ThreadB threadB = new ThreadB(lock);
            threadA.start();
            threadB.start();
    }
    
    private static class ThreadA extends Thread {
        Object obj;
    
        public ThreadA(Object lock) {
            obj = lock;
            setName("ThreadA");
        }
    
        @Override
        public void run() {
            super.run();
            System.out.println("Start Wait:" + Thread.currentThread().getName());
            try {
                synchronized (obj) {
                    obj.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Wait End:" + Thread.currentThread().getName());
        }
    }
    
        private static class ThreadB extends Thread {
            Object obj;
    
            public ThreadB(Object lock) {
                obj = lock;
                setName("ThreadB");
            }
    
        @Override
        public void run() {
            super.run();
            System.out.println("ThreadB Start:" + Thread.currentThread().getName());
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
            }
            System.out.println("After ThreadB Sleep 5S");
            synchronized (obj) {
                obj.notify();
            }
            System.out.println("ThreadB notify:" + Thread.currentThread().getName());
            }
        }
    }
    

運行結果:


示例2運行結果

從正確的結果可以看出极祸,在ThreadA和ThreadB同時啟動的時候慈格,ThreadB先運行,然后進入了Sleep遥金,后ThreadA運行浴捆,打印出了StartWait,然后處于wait狀態(tài)稿械,等到ThreadB從Sleep5秒醒來后选泻,調用object.notify,并且打印ThreadB notify,于是通知ThreadA页眯,接著ThreadA獲取到了Object的Monitor之后梯捕,結束運行。

2.錯誤的例子
讓B線程先啟動窝撵,并且在B線程執(zhí)行完之后傀顾,再繼續(xù)執(zhí)行主線程,之后再啟動A線程忿族,此時A線程中會調用wait方法锣笨,這時候線程A一直在等待notify而導致程序無法正常結束。

public class Test {
public static void main(String[] args) {
    Object lock = new Object();
    ThreadA threadA = new ThreadA(lock);
    ThreadB threadB = new ThreadB(lock);
    threadB.start();
    try {
        threadB.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    threadA.start();
}

private static class ThreadA extends Thread {
    Object obj;

    public ThreadA(Object lock) {
        obj = lock;
        setName("ThreadA");
    }

    @Override
    public void run() {
        super.run();
        System.out.println("Start Wait:" + Thread.currentThread().getName());
        try {
            synchronized (obj) {
                obj.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Wait End:" + Thread.currentThread().getName());
    }
}

private static class ThreadB extends Thread {
    Object obj;

    public ThreadB(Object lock) {
        obj = lock;
        setName("ThreadB");
    }

    @Override
    public void run() {
        super.run();
        System.out.println("ThreadB Start:" + Thread.currentThread().getName());
        try {
            Thread.sleep(5000L);
        } catch (InterruptedException e) {
        }
        System.out.println("After ThreadB Sleep 5S");
        synchronized (obj) {
            obj.notify();
        }
        System.out.println("ThreadB notify:" + Thread.currentThread().getName());
    }
}
}
示例2運行結果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末道批,一起剝皮案震驚了整個濱河市错英,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌隆豹,老刑警劉巖椭岩,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異璃赡,居然都是意外死亡判哥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門碉考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來塌计,“玉大人,你說我怎么就攤上這事侯谁⌒拷觯” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵墙贱,是天一觀的道長热芹。 經(jīng)常有香客問我,道長惨撇,這世上最難降的妖魔是什么伊脓? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮魁衙,結果婚禮上报腔,老公的妹妹穿的比我還像新娘。我一直安慰自己纺棺,他們只是感情好榄笙,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著祷蝌,像睡著了一般茅撞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天米丘,我揣著相機與錄音剑令,去河邊找鬼。 笑死拄查,一個胖子當著我的面吹牛吁津,可吹牛的內容都是我干的。 我是一名探鬼主播堕扶,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼碍脏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了稍算?” 一聲冷哼從身側響起典尾,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糊探,沒想到半個月后钾埂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡科平,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年褥紫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞪慧。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡髓考,死狀恐怖,靈堂內的尸體忽然破棺而出弃酌,到底是詐尸還是另有隱情绳军,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布矢腻,位于F島的核電站,受9級特大地震影響射赛,放射性物質發(fā)生泄漏多柑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一楣责、第九天 我趴在偏房一處隱蔽的房頂上張望竣灌。 院中可真熱鬧,春花似錦秆麸、人聲如沸初嘹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屯烦。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間驻龟,已是汗流浹背温眉。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留翁狐,地道東北人类溢。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像露懒,于是被迫代替她去往敵國和親闯冷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內容