Java Object的wait和notify方法使用詳解
Java Object的wait和notify方法
1 結(jié)論先交代出來(lái)
wait()、notify()/notifyAll()方法是Object的本地 final方法,無(wú)法被重寫。wait()使當(dāng)前線程阻塞,前提是必須先獲得鎖,一般配合synchronized關(guān)鍵字使用,一般在synchronized 同步代碼塊里使用wait()、notify()/notifyAll()方法。wait()需要被try catch包圍,中斷也可以使wait等待的線程喚醒。notify()和wait()的順序不能錯(cuò),如果A線程先執(zhí)行notify()方法,B線程在執(zhí)行wait()方法,那么B線程是無(wú)法被喚醒的。- 由于
wait()、notify()/notifyAll()在synchronized代碼塊執(zhí)行,說(shuō)明當(dāng)前線程一定是獲取了鎖的。
當(dāng)線程執(zhí)行 wait() 方法時(shí)候,會(huì)釋放當(dāng)前的鎖,然后讓出CPU,進(jìn)入等待狀態(tài)。只有當(dāng) notify() / notifyAll() 被執(zhí)行時(shí)候,才會(huì)喚醒一個(gè)或多個(gè)正處于等待狀態(tài)的線程,然后繼續(xù)往下執(zhí)行,直到執(zhí)行完 synchronized 代碼塊的代碼或是中途遇到 wait() ,再次釋放鎖。
也就是說(shuō),notify / notifyAll() 的執(zhí)行只是喚醒沉睡的線程,而不會(huì)立即釋放鎖,鎖的釋放要看代碼塊的具體執(zhí)行情況。所以在編程中,盡量在使用了 notify / notifyAll() 后立即退出臨界區(qū),以喚醒其他線程
2 notify 和 notifyAll 的區(qū)別
notify方法只喚醒一個(gè)等待(對(duì)象的)線程并使該線程開始執(zhí)行。所以如果有多個(gè)線程等待一個(gè)對(duì)象,這個(gè)方法只會(huì)喚醒其中一個(gè)線程,選擇哪個(gè)線程取決于操作系統(tǒng)對(duì)多線程管理的實(shí)現(xiàn)。
notifyAll 會(huì)喚醒所有等待(對(duì)象的)線程,盡管哪一個(gè)線程將會(huì)第一個(gè)處理取決于操作系統(tǒng)的實(shí)現(xiàn)。如果當(dāng)前情況下有多個(gè)線程需要被喚醒,推薦使用notifyAll 方法。
比如在生產(chǎn)者-消費(fèi)者里面的使用,每次都需要喚醒所有的消費(fèi)者或是生產(chǎn)者,以判斷程序是否可以繼續(xù)往下執(zhí)行。
3 wait沒(méi)有獲取鎖的情況
public class BB {
private void bb() {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("bbbb");
}
public static void main(String[] args) {
new BB().bb();
}
}異常:非法監(jiān)視器狀態(tài)異常
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.shigeqiu.demo.BB.bb(BB.java:10)
at com.shigeqiu.demo.BB.main(BB.java:19)
4 notify沒(méi)有獲取鎖的情況
public class BB {
private void bb() {
this.notify();
System.out.println("bbbb");
}
public static void main(String[] args) {
new BB().bb();
}
}異常:非法監(jiān)視器狀態(tài)異常
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.shigeqiu.demo.BB.bb(BB.java:9)
at com.shigeqiu.demo.BB.main(BB.java:14)
5 wait和notify執(zhí)行順序情況
public class WaitNotifyOrder {
public static void main(String[] args) throws InterruptedException {
MyLock myLock = new MyLock();
Thread threadA = new Thread(new ThreadA(myLock));
Thread threadB = new Thread(new ThreadB(myLock));
threadA.start();
Thread.sleep(1000);
threadB.start();
}
static class MyLock {
}
static class ThreadA implements Runnable {
private MyLock myLock;
public ThreadA(MyLock myLock) {
this.myLock = myLock;
}
@Override
public void run() {
synchronized (myLock) {
System.out.println("A before");
try {
myLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A after");
}
}
}
static class ThreadB implements Runnable {
private MyLock myLock;
public ThreadB(MyLock myLock) {
this.myLock = myLock;
}
@Override
public void run() {
synchronized (myLock) {
System.out.println('B');
myLock.notify();
}
}
}
}輸出如下:
A before
B
A after
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java高性能新一代構(gòu)建工具M(jìn)aven-mvnd(實(shí)踐可行版)
這篇文章主要介紹了Java高性能新一代構(gòu)建工具M(jìn)aven-mvnd(實(shí)踐可行版),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
Java對(duì)異常的認(rèn)識(shí)與異常的處理小結(jié)
Java程序在運(yùn)行時(shí)可能出現(xiàn)的錯(cuò)誤或非正常情況稱為異常,下面給大家介紹Java對(duì)異常的認(rèn)識(shí)與異常的處理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-06-06
Java保留兩位小數(shù)的實(shí)現(xiàn)方法
這篇文章主要介紹了 Java保留兩位小數(shù)的實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2017-06-06
SpringMVC 跨重定向請(qǐng)求傳遞數(shù)據(jù)的方法實(shí)現(xiàn)
這篇文章主要介紹了SpringMVC 跨重定向請(qǐng)求傳遞數(shù)據(jù)的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
MapStruct對(duì)象映射轉(zhuǎn)換解決Bean屬性拷貝性能問(wèn)題
無(wú)意間看到項(xiàng)目中有小伙伴用到了 MapStruct 來(lái)做對(duì)象映射轉(zhuǎn)換當(dāng)時(shí)我就很好奇,這個(gè)是什么框架,能夠解決什么問(wèn)題,帶著這兩個(gè)疑問(wèn)就有了下面的文章2022-02-02

