摘要:等待一段時間是否有線程喚醒鎖,如果沒有,超時自動喚醒。隨機喚醒等待隊列中的等待同一個鎖的一個線程,使這個線程退出等待隊列,進入可運行狀態(tài)。條件隊列中是處于等待狀態(tài)的線程,等待特定條件為真。在一般情況下,總應(yīng)該調(diào)用喚醒所有需要被喚醒的線程。
方法
java.lang.Object
public final native void wait() throws InterruptedException; public final native void wait(long millis, int nanos) throws InterruptedException; public final void wait(long millis) throws InterruptedException { wait(millis, 0); } public final native void notify(); public final native void notifyAll();
wait():使調(diào)用該方法的線程釋放鎖,從運行狀態(tài)退出,進入等待隊列,直到被喚醒。
wait(long timeout):等待一段時間是否有線程喚醒鎖,如果沒有,超時自動喚醒。
wait(long timeout, int nanos):等待喚醒時間納秒級別。
notify():隨機喚醒等待隊列中的等待同一個鎖的一個線程,使這個線程退出等待隊列,進入可運行狀態(tài)。
notifyAll():喚醒所有等待同樣鎖的所有線程,從等待隊列中退出,進入可運行狀態(tài)。
注意點在調(diào)用wait或者notify之前,必須獲得該對象的對象鎖,即,只能在同步方法中調(diào)用;
執(zhí)行完wait之后釋放對象鎖,所以其他線程可以獲得執(zhí)行機會,才能喚醒;
執(zhí)行notify之后,不會立即退出讓wait的線程執(zhí)行,必須要先把同步塊中的程序執(zhí)行完,退出同步塊,才會釋放鎖,讓等待線程執(zhí)行;
notify每次通知一個線程,多次調(diào)用通知線程數(shù)增加,可將wait線程全部喚醒。
原理每個對象都有個monitor,初始是0,執(zhí)行完synchronized值就是1。
wait/notify需要在獲得monitor的線程中才可以執(zhí)行。
所以,wait/notify需要在synchronized中執(zhí)行。
其中,wait又會釋放掉鎖,破壞掉同步。
跟synchronized關(guān)系synchronized代碼塊生成的字節(jié)碼,被monitorenter和monitorexit包圍,持有對象的monitor;
線程執(zhí)行wait/notify方法時,必須持有對象的monitor;
所以,wait/notify方法在synchronized同步塊中執(zhí)行,就持有了對象的鎖。
互斥和協(xié)同Java語言的同步機制在底層實現(xiàn)上只有兩種方式:互斥和協(xié)同。
互斥:即synchronized內(nèi)置鎖。
協(xié)同:即內(nèi)置條件隊列,wait/notify/notifyAll。
條件隊列中是處于等待狀態(tài)的線程,等待特定條件為真。每個Java對象都可以作為一個鎖,同樣每個Java對象都可以作為一個條件隊列。通過wait/notify/notifyAll來操作條件隊列。
可以理解為:有一個隊列,o.wait()就push進去,o.notify()就pull出來。
要調(diào)用條件隊列的任何一個方法,都必須要獲得對象上的鎖。
線程是用來工作的,不應(yīng)該處于等待狀態(tài),處于等待狀態(tài)的條件隊列中的線程,一定是執(zhí)行不下去的。
在while中等待while(condition is not true) { lock.wait() }
解釋:兩個消費者線程c1和c2,邏輯都是,判斷資源是否為空,是就wait,否就消費一個;某個時刻,兩個線程都進入等待隊列,然后生產(chǎn)者生產(chǎn)了一個資源,并執(zhí)行notifyAll,喚醒c1和c2都進入鎖池,c1先獲取鎖,執(zhí)行完消費掉資源,然后釋放鎖,此時,如果c2獲得鎖,如果是if邏輯,那么就會進入消費代碼,但是資源已經(jīng)被c1消費掉了,可能拋出異常。如果是while邏輯,則不會進入消費代碼,而是繼續(xù)等待。
在一般情況下,總應(yīng)該調(diào)用notifyAll喚醒所有需要被喚醒的線程。可能會喚醒其他一些線程,但這不影響程序的正確性,這些線程醒來之后,會檢查他們正在等待的條件(循環(huán)檢測),如果發(fā)現(xiàn)條件不滿足,就會繼續(xù)等待
顯示鎖和顯示條件隊列顯示鎖:Lock,對應(yīng)內(nèi)置鎖synchronized
顯示條件隊列:Condition,對應(yīng)內(nèi)置條件隊列,對應(yīng)方法是await, signal, signalAll
問題notifyAll喚醒所有線程,但不是所有線程都能執(zhí)行,必須要等待對象鎖被釋放,獲取鎖之后才能執(zhí)行。可以說,notifyAll讓線程進入鎖池。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/70909.html
摘要:在這個等待通知機制中,我們需要考慮以下四個要素。何時等待線程要求的條件不滿足就等待。是會隨機地通知等待隊列中的一個線程,而會通知等待隊列中的所有線程。 由上一篇文章你應(yīng)該已經(jīng)知道,在 破壞占用且等待條件 的時候,如果轉(zhuǎn)出賬本和轉(zhuǎn)入賬本不滿足同時在文件架上這個條件,就用死循環(huán)的方式來循環(huán)等待,核心代碼如下: // 一次性申請轉(zhuǎn)出賬戶和轉(zhuǎn)入賬戶,直到成功 while(!actr.apply...
摘要:前言上一篇文章我們講了的同步代碼塊這一篇我們來看看同步代碼塊之間的協(xié)作與通信閱讀本篇前你需要知道什么是同步代碼塊什么是監(jiān)視器鎖還不是很了解的同學(xué)建議先去看一看上一篇文章本文的源碼基于系列文章目錄概述在中我們可以使用這個方法來實現(xiàn)同步代碼塊之 前言 上一篇文章我們講了java的同步代碼塊, 這一篇我們來看看同步代碼塊之間的協(xié)作與通信. 閱讀本篇前你需要知道什么是同步代碼塊, 什么是監(jiān)視器...
摘要:不釋放持有的鎖,釋放鎖。在調(diào)用方法前,必須持有鎖,調(diào)用喚醒,也要持有鎖。休眠一定時間后,進入就緒狀態(tài)。這兩個都能被方法中斷當前狀態(tài)。用法方獲取鎖判斷條件,不滿足繼續(xù)滿足執(zhí)行其他業(yè)務(wù)方獲取鎖改變條件通知為什么是而不是會一直循環(huán),直到條件滿足。 sleep和wait sleep是Thread類的方法,wait是Object的方法。 sleep可以到處使用,wait必須是在同步方法或者代碼...
摘要:如果有其它線程調(diào)用了相同對象的方法,那么處于該對象的等待池中的線程就會全部進入該對象的鎖池中,從新爭奪鎖的擁有權(quán)。 wait,notify 和 notifyAll,這些在多線程中被經(jīng)常用到的保留關(guān)鍵字,在實際開發(fā)的時候很多時候卻并沒有被大家重視,而本文則是對這些關(guān)鍵字的使用進行描述。 存在即合理 在java中,每個對象都有兩個池,鎖池(monitor)和等待池(waitset),每個...
摘要:用法中規(guī)定,在調(diào)用者三個方法時,當前線程必須獲得對象鎖。作用方法作用線程自動釋放占有的對象鎖,并等待。當生產(chǎn)者生產(chǎn)了一個數(shù)據(jù)或者消費者消費了一個數(shù)據(jù)之后,使用方法來通知所有等待當前對象鎖的線程,但是一次只會有一個等待的線程能拿到鎖。 基礎(chǔ)知識 首先我們需要知道,這幾個都是Object對象的方法。換言之,Java中所有的對象都有這些方法。 public final native void...
閱讀 2512·2021-11-22 13:53
閱讀 1191·2021-09-22 16:06
閱讀 1440·2021-09-02 15:21
閱讀 1978·2019-08-30 15:55
閱讀 3190·2019-08-29 11:19
閱讀 1971·2019-08-26 13:23
閱讀 1000·2019-08-23 18:23
閱讀 1809·2019-08-23 16:06