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

二、Park & Unpark的使用
1、基本使用
它們是 LockSupport 類中的方法
// 暫停當(dāng)前線程 LockSupport.park(); // 恢復(fù)某個線程的運(yùn)行 LockSupport.unpark(暫停線程對象)
先 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是成對出現(xiàn),但是是不分先后的
2、特點(diǎn)
與 Object 的 wait & notify 相比
- wait,notify 和 notifyAll 必須配合 Object Monitor 一起使用,而 park,unpark 不必
- park & unpark 是以線程為單位來【阻塞】和【喚醒】線程(喚醒的時候可以傳一個線程作為參數(shù)),而 notify 只能隨機(jī)喚醒一個等待線程,notifyAll 是喚醒所有等待線程,就不那么【精確】
- park & unpark 可以先 unpark,而 wait & notify 不能先 notify
到此這篇關(guān)于Java多線程中的wait、notify和park、unpark的使用詳解的文章就介紹到這了,更多相關(guān)Java多線程wait、notify和park內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于jackson序列化和feign返回值的問題
這篇文章主要介紹了關(guān)于jackson序列化和feign返回值的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringCloud容器化服務(wù)發(fā)現(xiàn)及注冊實現(xiàn)方法解析
這篇文章主要介紹了SpringCloud容器化服務(wù)發(fā)現(xiàn)及注冊實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08
解決mac最新版intellij idea崩潰閃退crash的問題
這篇文章主要介紹了解決mac最新版intellij idea崩潰閃退crash的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
java使double保留兩位小數(shù)的多方法 java保留兩位小數(shù)
這篇文章主要介紹了java使double類型保留兩位小數(shù)的方法,大家參考使用吧2014-01-01

