日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

为什么wait/notify必须要和synchronized一起使用?

發(fā)布時間:2025/3/11 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为什么wait/notify必须要和synchronized一起使用? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者 | 磊哥

來源 | Java面試真題解析(ID:aimianshi666)

轉(zhuǎn)載請聯(lián)系授權(quán)(微信ID:GG_Stone)

在多線程編程中,wait 方法是讓當(dāng)前線程進(jìn)入休眠狀態(tài),直到另一個線程調(diào)用了 notify 或 notifyAll 方法之后,才能繼續(xù)恢復(fù)執(zhí)行。而在 Java 中,wait 和 notify/notifyAll 有著一套自己的使用格式要求,也就是在使用 wait 和 notify(notifyAll 的使用和 notify 類似,所以下文就只用 notify 用來指代二者)必須配合 synchronized 一起使用才行。

wait/notify基礎(chǔ)使用

wait 和 notify 的基礎(chǔ)方法如下:

Object?lock?=?new?Object(); new?Thread(()?->?{synchronized?(lock)?{try?{System.out.println("wait?之前");//?調(diào)用?wait?方法lock.wait();System.out.println("wait?之后");}?catch?(InterruptedException?e)?{e.printStackTrace();}} }).start();Thread.sleep(100); synchronized?(lock)?{System.out.println("執(zhí)行?notify");//?調(diào)用?notify?方法lock.notify(); }

以上代碼的執(zhí)行結(jié)果如下圖所示:

wait/notify和synchronized一起用?

那問題來了,是不是 wait 和 notify 一定要配合 synchronized 一起使用呢?wait 和 notify 單獨(dú)使用行不行呢?我們嘗試將以上代碼中的 synchronized 代碼行刪除,實現(xiàn)代碼如下:初看代碼好像沒啥問題,編譯器也沒報錯,好像能“正常使用”,然而當(dāng)我們運(yùn)行以上程序時就會發(fā)生如下錯誤:從上述結(jié)果可以看出:無論是 wait 還是 notify,如果不配合 synchronized 一起使用,在程序運(yùn)行時就會報 IllegalMonitorStateException 非法的監(jiān)視器狀態(tài)異常,而且 notify 也不能實現(xiàn)程序的喚醒功能了。

原因分析

從上述的報錯信息我們可以看出,JVM 在運(yùn)行時會強(qiáng)制檢查 wait 和 notify 有沒有在 synchronized 代碼中,如果沒有的話就會報非法監(jiān)視器狀態(tài)異常(IllegalMonitorStateException),但這也僅僅是運(yùn)行時的程序表象,那為什么 Java 要這樣設(shè)計呢?其實這樣設(shè)計的原因就是為了防止多線程并發(fā)運(yùn)行時,程序的執(zhí)行混亂問題。初看這句話,好像是用來描述“鎖”的。然而實際情況也是如此,wait 和 notify 引入鎖就是來規(guī)避并發(fā)執(zhí)行時程序的執(zhí)行混亂問題的。那這個“執(zhí)行混亂問題”到底是啥呢?接下來我們繼續(xù)往下看。

wait和notify問題復(fù)現(xiàn)

我們假設(shè) wait 和 notify 可以不加鎖,我們用它們來實現(xiàn)一個自定義阻塞隊列。這里的阻塞隊列是指讀操作阻塞,也就是當(dāng)讀取數(shù)據(jù)時,如果有數(shù)據(jù)就返回數(shù)據(jù),如果沒有數(shù)據(jù)則阻塞等待數(shù)據(jù),實現(xiàn)代碼如下:

class?MyBlockingQueue?{//?用來保存數(shù)據(jù)的集合Queue<String>?queue?=?new?LinkedList<>();/***?添加方法*/public?void?put(String?data)?{//?隊列加入數(shù)據(jù)queue.add(data);?//?喚醒線程繼續(xù)執(zhí)行(這里的線程指的是執(zhí)行?take?方法的線程)notify();?//?③}/***?獲取方法(阻塞式執(zhí)行)*?如果隊列里面有數(shù)據(jù)則返回數(shù)據(jù),如果沒有數(shù)據(jù)就阻塞等待數(shù)據(jù)*?@return*/public?String?take()?throws?InterruptedException?{//?使用?while?判斷是否有數(shù)據(jù)(這里使用?while?而非?if?是為了防止虛假喚醒)while?(queue.isEmpty())?{?//?①??//?沒有任務(wù),先阻塞等待wait();?//?②}return?queue.remove();?//?返回數(shù)據(jù)} }

注意上述代碼,我們在代碼中標(biāo)識了三個關(guān)鍵執(zhí)行步驟:①:判斷隊列中是否有數(shù)據(jù);②:執(zhí)行 wait 休眠操作;③:給隊列中添加數(shù)據(jù)并喚醒阻塞線程。如果不強(qiáng)制要求添加 synchronized,那么就會出現(xiàn)如下問題:

步驟線程1線程2
1執(zhí)行步驟 ① 判斷當(dāng)前隊列中沒有數(shù)據(jù)
2
執(zhí)行步驟 ③ 將數(shù)據(jù)添加到隊列,并喚醒線程1繼續(xù)執(zhí)行
3執(zhí)行步驟 ② 線程 1 進(jìn)入休眠狀態(tài)

從上述執(zhí)行流程看出問題了嗎?如果 wait 和 notify 不強(qiáng)制要求加鎖,那么在線程 1 執(zhí)行完判斷之后,尚未執(zhí)行休眠之前,此時另一個線程添加數(shù)據(jù)到隊列中。然而這時線程 1 已經(jīng)執(zhí)行過判斷了,所以就會直接進(jìn)入休眠狀態(tài),從而導(dǎo)致隊列中的那條數(shù)據(jù)永久性不能被讀取,這就是程序并發(fā)運(yùn)行時“執(zhí)行結(jié)果混亂”的問題。然而如果配合 synchronized 一起使用的話,代碼就會變成以下這樣:

class?MyBlockingQueue?{//?用來保存任務(wù)的集合Queue<String>?queue?=?new?LinkedList<>();/***?添加方法*/public?void?put(String?data)?{synchronized?(MyBlockingQueue.class)?{//?隊列加入數(shù)據(jù)queue.add(data);//?為了防止?take?方法阻塞休眠,這里需要調(diào)用喚醒方法?notifynotify();?//?③}}/***?獲取方法(阻塞式執(zhí)行)*?如果隊列里面有數(shù)據(jù)則返回數(shù)據(jù),如果沒有數(shù)據(jù)就阻塞等待數(shù)據(jù)*?@return*/public?String?take()?throws?InterruptedException?{synchronized?(MyBlockingQueue.class)?{//?使用?while?判斷是否有數(shù)據(jù)(這里使用?while?而非?if?是為了防止虛假喚醒)while?(queue.isEmpty())?{??//?①//?沒有任務(wù),先阻塞等待wait();?//?②}}return?queue.remove();?//?返回數(shù)據(jù)} }

這樣改造之后,關(guān)鍵步驟 ① 和關(guān)鍵步驟 ② 就可以一起執(zhí)行了,從而當(dāng)線程執(zhí)行了步驟 ③ 之后,線程 1 就可以讀取到隊列中的那條數(shù)據(jù)了,它們的執(zhí)行流程如下:

步驟線程1線程2
1執(zhí)行步驟 ① 判斷當(dāng)前隊列沒有數(shù)據(jù)
2執(zhí)行步驟 ② 線程進(jìn)入休眠狀態(tài)
3
執(zhí)行步驟 ③ 將數(shù)據(jù)添加到隊列,并執(zhí)行喚醒操作
4線程被喚醒,繼續(xù)執(zhí)行
5判斷隊列中有數(shù)據(jù),返回數(shù)據(jù)

這樣咱們的程序就可以正常執(zhí)行了,這就是為什么 Java 設(shè)計一定要讓 wait 和 notify 配合上 synchronized 一起使用的原因了。

總結(jié)

本文介紹了 wait 和 notify 的基礎(chǔ)使用,以及為什么 wait 和 notify/notifyAll 一定要配合 synchronized 使用的原因。如果 wait 和 notify/notifyAll 不強(qiáng)制和 synchronized 一起使用,那么在多線程執(zhí)行時,就會出現(xiàn) wait 執(zhí)行了一半,然后又執(zhí)行了添加數(shù)據(jù)和 notify 的操作,從而導(dǎo)致線程一直休眠的缺陷。

是非審之于己,毀譽(yù)聽之于人,得失安之于數(shù)。

公眾號:Java面試真題解析

面試合集:https://gitee.com/mydb/interview

往期推薦 面試突擊23:說一下線程生命周期,以及轉(zhuǎn)換過程?面試突擊22:為什么start方法不能重復(fù)調(diào)用?而run方法卻可以?有哪些創(chuàng)建線程的方法?推薦使用哪種?求點(diǎn)贊、在看、分享三連

總結(jié)

以上是生活随笔為你收集整理的为什么wait/notify必须要和synchronized一起使用?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美成人午夜精品久久久 | 麻豆免费在线 | 亚洲男人天堂久久 | 亚洲精品在线观 | 扩阴视频 | 国产福利午夜 | 亚洲精品视频一区二区 | 最新中文av | 久久久激情网 | 国产一区二区视频在线 | 哪个网站可以看毛片 | 51ⅴ精品国产91久久久久久 | h视频免费在线 | 国产综合精品一区二区三区 | 国产精品毛片视频 | 亚洲精品国产99 | 亚洲二区中文字幕 | 环太平洋3:泰坦崛起 | 久久婷婷五月国产色综合激情 | 伊人久久麻豆 | 人妻精品久久久久中文字幕69 | 黄色片网站在线 | 147人体做爰大胆图片成人 | 中文字幕 人妻熟女 | 哈利波特3在线观看免费版英文版 | 97精品国产97久久久久久粉红 | 伊人91视频 | 高清久久久| 伊人久久天堂 | 色爽| 少女忠诚电影高清免费 | 国产三级视频在线播放 | 国产suv精品一区二区 | 欧美大浪妇猛交饥渴大叫 | 久久久精品视频一区 | 欧洲视频一区二区 | 亚洲国产精品99久久久久久久久 | 精品成人在线观看 | 日韩欧美视频 | 人与禽一级全黄 | 国产精品无码影院 | 亚洲美女屁股眼交3 | 密臀av一区二区 | 男女视频免费网站 | 一级伦理农村妇女愉情 | 国产原创精品 | 亚洲精品国产熟女久久久 | 一本大道综合伊人精品热热 | 国产美女网站视频 | 久久官网 | 特级做a爰片毛片免费69 | 天天看夜夜爽 | 久久888 | 女人毛片视频 | 成年人免费网站视频 | 免费观看日本 | 无码国产伦一区二区三区视频 | 操欧美老逼 | 欧美一级黄色录像 | 国产99久一区二区三区a片 | 欧美精品免费一区二区三区 | 亚洲第一综合网 | 国产精品99无码一区二区视频 | 国产成人精品网站 | 奇米888一区二区三区 | 九九色| 又黄又骚的视频 | 成人公开免费视频 | 免费在线观看毛片视频 | 女同亚洲精品一区二区三 | 亚洲国产精品久久久久爰性色 | 四虎免看黄| 亚洲精品成人在线 | 男人日女人逼 | 成人欧美一区二区三区 | 中文字幕一区二区三区日韩精品 | 日本视频www色 | sm乳奴虐乳调教bdsm | 国产精品一区二区精品 | 在线观看免费视频一区二区 | xxxx国产片| 久久久久久久国产视频 | 18无码粉嫩小泬无套在线观看 | 亚洲大胆 | 色婷婷av一区二区三区gif | www.97色| xxxxxxxx黄色片| 久久依人 | 免费啪啪小视频 | 国产精品亚洲专区无码牛牛 | 熟妇人妻系列aⅴ无码专区友真希 | 超碰在线一区 | 老公吃小头头视频免费观看 | 日本东京热一区二区 | 日本免费一区二区视频 | 亚洲视屏在线观看 | 五月婷婷六月激情 | 日韩精品在线免费观看视频 | 久久国产一区 |