Java多線程中的wait、notify和park、unpark的使用詳解
一、wait & notify的使用
1、API介紹
- obj.wait() 讓進(jìn)入 object 監(jiān)視器的線程到 waitSet 等待
- obj.wait(n) 讓進(jìn)入 object 監(jiān)視器的線程到 waitSet 等待,n秒后還沒(méi)有被喚醒的話,則自動(dòng)醒來(lái)
- obj.notify() 在 object 上正在 waitSet 等待的線程中挑一個(gè)喚醒
- obj.notifyAll() 讓 object 上正在 waitSet 等待的線程全部喚醒
它們都是線程之間進(jìn)行協(xié)作的手段,都屬于 Object 對(duì)象的方法。
必須獲得此對(duì)象的鎖,才能調(diào)用這幾個(gè)方法 wait() 方法會(huì)釋放對(duì)象的鎖,進(jìn)入 WaitSet 等待區(qū),從而讓其他線程就機(jī)會(huì)獲取對(duì)象的鎖。
無(wú)限制等待,直到notify 為止 wait(long n) 有時(shí)限的等待, 到 n 毫秒后結(jié)束等待,或是被 notify notify 只能隨機(jī)喚醒一個(gè) WaitSet 中的線程,這時(shí)如果有其它線程也在等待,那么就可能喚醒不了正確的線程,稱之為【虛假喚醒】
2、demo
@Slf4j(topic = "c.TestCorrectPosture")
public class TestCorrectPostureStep5 {
static final Object room = new Object();
static boolean hasCigarette = false;
static boolean hasTakeout = false;
public static void main(String[] args) {
new Thread(() -> {
synchronized (room) {
log.debug("有煙沒(méi)?[{}]", hasCigarette);
while (!hasCigarette) {
log.debug("沒(méi)煙,先歇會(huì)!");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("有煙沒(méi)?[{}]", hasCigarette);
if (hasCigarette) {
log.debug("可以開(kāi)始干活了");
} else {
log.debug("沒(méi)干成活...");
}
}
}, "小南").start();
new Thread(() -> {
synchronized (room) {
Thread thread = Thread.currentThread();
log.debug("外賣(mài)送到?jīng)]?[{}]", hasTakeout);
while (!hasTakeout) {
log.debug("沒(méi)外賣(mài),先歇會(huì)!");
try {
room.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("外賣(mài)送到?jīng)]?[{}]", hasTakeout);
if (hasTakeout) {
log.debug("可以開(kāi)始干活了");
} else {
log.debug("沒(méi)干成活...");
}
}
}, "小女").start();
sleep(1);
new Thread(() -> {
synchronized (room) {
hasTakeout = true;
log.debug("外賣(mài)到了噢!");
room.notifyAll();
}
}, "送外賣(mài)的").start();
}
}
2、多線程模式
模式之保護(hù)性暫停 模式之生產(chǎn)者消費(fèi)者
3、wait和notify的原理

二、Park & Unpark的使用
1、基本使用
它們是 LockSupport 類中的方法
// 暫停當(dāng)前線程 LockSupport.park(); // 恢復(fù)某個(gè)線程的運(yùn)行 LockSupport.unpark(暫停線程對(duì)象)
先 park 再 unpark
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("start...");
sleep(1);
log.debug("park...");
LockSupport.park();
log.debug("resume...");
}, "t1");
t1.start();
sleep(4);
log.debug("unpark...");
LockSupport.unpark(t1);
}
先 unpark 再 park
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("start...");
sleep(2);
log.debug("park...");
LockSupport.park();
log.debug("resume...");
}, "t1");
t1.start();
sleep(1);
log.debug("unpark...");
LockSupport.unpark(t1);
}
結(jié)論:park和unpark是成對(duì)出現(xiàn),但是是不分先后的
2、特點(diǎn)
與 Object 的 wait & notify 相比
- wait,notify 和 notifyAll 必須配合 Object Monitor 一起使用,而 park,unpark 不必
- park & unpark 是以線程為單位來(lái)【阻塞】和【喚醒】線程(喚醒的時(shí)候可以傳一個(gè)線程作為參數(shù)),而 notify 只能隨機(jī)喚醒一個(gè)等待線程,notifyAll 是喚醒所有等待線程,就不那么【精確】
- park & unpark 可以先 unpark,而 wait & notify 不能先 notify
到此這篇關(guān)于Java多線程中的wait、notify和park、unpark的使用詳解的文章就介紹到這了,更多相關(guān)Java多線程wait、notify和park內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于jackson序列化和feign返回值的問(wèn)題
這篇文章主要介紹了關(guān)于jackson序列化和feign返回值的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringCloud容器化服務(wù)發(fā)現(xiàn)及注冊(cè)實(shí)現(xiàn)方法解析
這篇文章主要介紹了SpringCloud容器化服務(wù)發(fā)現(xiàn)及注冊(cè)實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
java分頁(yè)攔截類實(shí)現(xiàn)sql自動(dòng)分頁(yè)
這篇文章主要為大家詳細(xì)介紹了java分頁(yè)攔截類可以實(shí)現(xiàn)sql自動(dòng)分頁(yè),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
你應(yīng)該知道的21個(gè)Java核心技術(shù)
Java的21個(gè)核心技術(shù)點(diǎn),你知道嗎?這篇文章主要為大家詳細(xì)介紹了Java核心技術(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
解決mac最新版intellij idea崩潰閃退crash的問(wèn)題
這篇文章主要介紹了解決mac最新版intellij idea崩潰閃退crash的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
java使double保留兩位小數(shù)的多方法 java保留兩位小數(shù)
這篇文章主要介紹了java使double類型保留兩位小數(shù)的方法,大家參考使用吧2014-01-01

