java notify喚醒原理_Java wait和notify虛假喚醒原理

自己在此記錄一下,方便日后復習。

虛假喚醒的概念

jdk官方文檔解釋:

3q02d532yca.jpg

所以說在wait和notify一塊使用時,如果使用if作為條件時,會有虛假喚醒的情況發生,所以必須使用while作為循環條件。下面來舉例實驗:

首先,創建一個資源類:(在多線程中,一般都是資源類和線程操作解耦,不放在用同一個類中,只有在線程操作資源類時,才會創建資源類的對象)

package com.test;

/**

* 資源類

* @author Huxudong

* @createTime 2020-04-01 21:57:39

**/

public class Resource {

/** 產品數 */

private int product = 0;

/** 進貨 */

public synchronized void get() {

if(product >= 10) {

System.out.println(Thread.currentThread().getName()+":"+"產品已滿!");

/** 當商品已經滿的時候,進貨線程掛起 */

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/** 進貨 */

System.out.println(Thread.currentThread().getName()+":"+ ++product);

/** 喚醒其他線程 */

this.notifyAll();

}

/** 售貨 */

public synchronized void sale() {

if(product <= 0) {

System.out.println(Thread.currentThread().getName()+":"+"產品已空");

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/** 售貨 */

System.out.println(Thread.currentThread().getName()+":"+ --product);

/** 喚醒其他線程 */

this.notify();

}

}

然后再創建線程來操作我們的資源類(通過java8新特性Lambda表達式直接創建)

package com.test;

import java.util.concurrent.TimeUnit;

/**

* 線程操作資源類,實現線程與資源類的解耦合

* @author Huxudong

* @createTime 2020-04-01 23:13:54

**/

public class TestPc {

public static void main(String[] args) {

Resource resource = new Resource();

new Thread(()->{

for (int i = 0; i < 20; i++) {

try {

/** 睡眠,便于觀察結果 */

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

resource.get();

}

},"生產者A").start();

new Thread(()->{

for (int i = 0; i < 20; i++) {

resource.sale();

}

},"消費者C").start();

new Thread(()->{

for (int i = 0; i < 20; i++) {

resource.get();

}

},"生產者B").start();

new Thread(()->{

for (int i = 0; i < 20; i++) {

resource.sale();

}

},"消費者D").start();

}

}

先來看看如果使用if條件會發生什么:

e5ed96fa20ba74a04a21c25b69c2b390.png

對,你沒看錯,怎么可能會出現負數呢,這肯定是不對的。冷靜下來分析一下,還是有點頭緒,知道哪里出現了問題的(那你是一個處事不驚的人,很厲害)。

來,分析一下,一開始先調用了消費者C,D線程(因為我們寫了睡眠在生產者中),消費者此時發現此時product資源為0,所以,消費者C,D這兩個兄弟,沒辦法只能調用wait方法,睡眠了,并且釋放了鎖。

但是此時第一個消費者已經蘇醒了,發動機開始生產產品了,并且生產之后,又喚醒了所有等待的消費者線程。這消費者C,D兩兄弟終于蘇醒了,D哥們先獲得了鎖,所以就先消費了一個產品,然后就又發現沒有產品了,又傷心的休眠去了,但是不要忘了,此時還有一個C哥們被喚醒了啊,你喚醒了人家,人家總的干點什么事情吧,不然這多難受,剛好不巧的是,此時的判斷條件是if,所以此時C哥們便不受條件的約束,接著上面自己睡眠的代碼處執行,毅然決然的又去消費了一個產品,原來D哥們消費后,就已經為0了,這個C哥們再去消費減一,不就是-1了嗎,以此類推分析。發現如果判斷條件用不好,此時喚醒的C哥們就相當于虛假喚醒的了,會給程序帶來不可預估的錯誤。所以在這里判斷必須要使用while,先來看看把if換成while的結果。

42oknqsgx3b.jpg

這回結果就比較正常了,為什么使用while就可以呢,因為像上文所說,即使喚醒了所有的消費者線程,此時會不停while循環判斷,如果此時條件是為0,那么C哥們就不能出while,那么他也就不回執行下面消費產品的減減操作了,那么就會避免了這種錯誤。這也是官方提倡的在使用wait 和notifyAll的時候,必須使用while循環條件判斷。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持聚米學院。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/541020.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/541020.shtml
英文地址,請注明出處:http://en.pswp.cn/news/541020.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C#里面的三種定時計時器:Timer

在.NET中有三種計時器&#xff1a;1、System.Windows.Forms命名空間下的Timer控件&#xff0c;它直接繼承自Componet。Timer控件只有綁定了Tick事件和設置EnabledTrue后才會自動計時&#xff0c;停止計時可以用Stop()方法控制&#xff0c;通過Stop()停止之后&#xff0c;如果想…

wireshark rto_RTO的完整形式是什么?

wireshark rtoRTO&#xff1a;地區運輸辦公室/公路運輸辦公室 (RTO: Regional Transport Office/ Road Transport Office) RTO is an abbreviation of the Regional Transport Office. It is an Indian Government departmental organization that is responsible for upholdin…

java8 json轉xml_2019-08-17java對象與json,xml互轉

依賴的jar包&#xff0c;jackson-all-1.7.6.jar,xstream-1.4.4.jar下載地址:鏈接&#xff1a;https://pan.baidu.com/s/1LflD135qlQiIPGXw5XwDmw提取碼&#xff1a;6v29復制這段內容后打開百度網盤手機App&#xff0c;操作更方便哦package json_xml;import com.thoughtworks.xs…

10.8-全棧Java筆記:序列化/反序列化的步驟和實例

本節我們詳細講解10.3節中提到的序列化和反序列化操作。序列化和反序列化是什么當兩個進程遠程通信時&#xff0c;彼此可以發送各種類型的數據。 無論是何種類型的數據&#xff0c;都會以二進制序列的形式在網絡上傳送。比如&#xff0c;我們可以通過http協議發送字符串信息&am…

有效的網絡推廣超級實用方法

我叫龍雨&#xff0c;先后在百度搜狗工作過3年&#xff0c;后來一直負責一家公司的的網絡營銷!不知道大家有沒有聽過111>3這樣一個概念&#xff0c;簡單來說一下這概念!第一呢就是自己的資源&#xff0c;把自己的資源維護好開發好;第二就是網絡營銷&#xff0c;網絡營銷利用…

什么為java運行時的環境_什么是JRE?Java運行時環境簡介(一)

Java開發工具包(JDK),Java虛擬機(JVM)和Java運行時環境(JRE)共同構成了用于開發和運行Java應用程序的Java平臺組件的強大功能.實際上,運行時環境是一種旨在運行其他軟件的軟件.作為Java的運行時環境,JRE包含Java類庫,Java類加載器和Java虛擬機.在這個系統中:的類加載器是負責正…

c語言atoll函數怎么用_C ++中帶有示例的atoll()函數

c語言atoll函數怎么用C Atoll()函數 (C atoll() function) atoll() function is a library function of cstdlib header. It is used to convert the given string value to the integer value. It accepts a string containing an integer (integral) number and returns its…

看清美國“黑客帝國”的真面目

“維基揭秘”網站近日發布了近9000份據稱屬于美國中央情報局的機密文件&#xff0c;顯示中情局擁有強大的黑客攻擊能力&#xff0c;秘密侵入了手機、電腦、智能電視等眾多智能設備。繼美國國家安全局承包商前雇員斯諾登曝光國安局“棱鏡”等監控計劃之后&#xff0c;此次曝光再…

python 示例_帶有示例的Python File close()方法

python 示例文件close()方法 (File close() Method) close() method is an inbuilt method in Python, it is used to flush and close the IO object (file). If we close a closed file it has no effect. close()方法是Python中的內置方法&#xff0c;用于刷新和關閉IO對象(…

linux上mysql分區磁盤位置_Linux下Oracle軟件、數據文件等所在的磁盤分區空間不足的解決思路...

虛擬機中的ORACLE運行的久了&#xff0c;歸檔、數據文件不斷增長&#xff0c;原來安裝ORACLE的分區空間不足。此時可以重新向虛擬機增加一塊硬盤&#xff0c;將OR虛擬機中的Oracle運行的久了&#xff0c;歸檔、數據文件不斷增長&#xff0c;原來安裝ORACLE的分區空間不足。此時…

FloatingActionMenu 向上彈出菜單

本人在github上找到了一個FloatingActionsMenu,精簡了其效果&#xff08;原效果有上下左右四個方向&#xff09;僅僅保留向上的效果&#xff0c;并做了一定的優化。github上的源代碼&#xff1a;地址 &#xff0c;精簡后的源代碼地址:源代碼地址。 轉載于:https://www.cnblogs.…

java uuid靜態方法_Java UUID的variant()方法和示例

java uuid靜態方法UUID類variant()方法 (UUID Class variant() method) variant() method is available in java.util package. variant()方法在java.util包中可用。 variant() method is used to get the variant number linked with this UUID. variant()方法用于獲取與此UUI…

java程序服務不能啟動不了_JavaService.exe注冊的windows服務無法啟動問題

最近開發了個java程序&#xff0c;打成 jar 包想要在windows后臺運行&#xff0c;于是使用JavaService.exe進行windows服務注冊&#xff0c;服務注冊很成功&#xff0c;但是在啟動時顯示“服務無法啟動”&#xff0c;為此耗費了大量的時間與精力&#xff0c;終于發現問題所在&a…

給孩子一束安全的光 明基WiT MindDuo親子共讀燈首發評測

論一束光的重要性你該聽聽一個高度近視孩子的自述&#xff0c;論童年陪伴的重要性你該聽聽一個留守兒童的自述&#xff0c;改善孩子童年的全球第一盞親子共讀臺燈&#xff0c;貼合孩子與家長的心靈&#xff0c;量身打造每一種情境的光線去感受孩子成長學習過程 一個高度近視眼孩…

Java Scanner next()方法與示例

掃描儀類的next()方法 (Scanner Class next() method) Syntax: 句法&#xff1a; public String next();public String next(Pattern patt);public String next(String patt);next() method is available in java.util package. next()方法在java.util包中可用。 next() metho…

mysql怎樣查表的模式_mysql常用基礎操作語法(四)--對數據的簡單無條件查詢及庫和表查詢【命令行模式】...

1、mysql簡單的查詢&#xff1a;select 字段1&#xff0c;字段2... from tablename;如果字段那里寫一個*&#xff0c;代表查詢所有的字段&#xff0c;等同于指定出所有的字段名&#xff0c;因此如果要查詢所有字段的數據&#xff0c;一般都是用*。2、去重查詢&#xff1a;selec…

Google再次從官方商店下架偽裝成合法程序的惡意應用

本月內的第二次&#xff0c;Google 從官方應用商店 Google Play 移除了偽裝成合法程序的惡意應用。被移除的應用都屬于名叫 Ztorg 的 Android 惡意程序家族&#xff0c;能利用已知的漏洞 root 被感染的設備&#xff0c;使其很難被刪除。自去年 9 月以來&#xff0c;Ztorg 惡意應…

java scanner_Java Scanner skip()方法與示例

java scanner掃描儀類skip()方法 (Scanner Class skip() method) Syntax: 句法&#xff1a; public Scanner skip(Pattern patt);public Scanner skip(String patt);skip() method is available in java.util package. skip()方法在java.util包中可用。 skip(Pattern patt) me…

MySQL文件后_MySQL誤刪除文件后,如何恢復

MySQL在運行中&#xff0c;如果誤刪除數據文件&#xff0c;只有服務進程沒有退出&#xff0c;那么就有辦法將其恢復。首先介紹Linux下lsof&#xff1a;他可以顯示打開的文件和網絡連接。其次/proc目錄包含了反映內核和進程樹的各種文件。/proc/504目錄包含的是PID是504的進程信…

【載譽】致遠互聯榮獲“2017最佳協同管理解決方案”殊榮

6月15日&#xff0c;一年一度的大連軟交會于大連市世界博覽廣場盛大舉行。“2017企業服務創新論壇”作為軟交會最重要的組成部分之一&#xff0c;本年度以“守正出新——通往基業長青的數字化選擇”為主題&#xff0c;吸引到近200位企業級服務領域的企業家及高管參加。致遠互聯…