Java等待喚醒機(jī)制原理實(shí)例解析
這篇文章主要介紹了Java等待喚醒機(jī)制原理實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
線程的狀態(tài)
首先了解一下什么是線程的狀態(tài),線程狀態(tài)就是當(dāng)線程被創(chuàng)建(new),并且啟動(dòng)(start)后,它不是一啟動(dòng)就進(jìn)入了執(zhí)行狀態(tài)(run),也不是一直都處于執(zhí)行狀態(tài)。
這里說一下Java 的Thread類里面有一個(gè)State方法,這個(gè)方法里面涵蓋了6種線程的狀態(tài),如下:
public enum State { // 尚未啟動(dòng)的線程的線程狀態(tài)。 NEW, // 可運(yùn)行線程的線程狀態(tài)。 RUNNABLE, // 線程的線程狀態(tài)被阻塞,等待監(jiān)視器鎖定。 BLOCKED, // 等待線程的線程狀態(tài)。 WAITING, // 具有指定等待時(shí)間的等待線程的線程狀態(tài)。 TIMED_WAITING, // 終止線程的線程狀態(tài)。 TERMINATED; }
導(dǎo)致這六種線程狀態(tài)發(fā)生的條件
New -- 新建
線程剛被創(chuàng)建,不過還沒有被啟動(dòng)(還沒有調(diào)用start方法)
Runnable -- 可運(yùn)行
處于可運(yùn)行狀態(tài)的線程正在Java虛擬機(jī)中執(zhí)行,但是它可能正在等待來自操作系統(tǒng)(例如處理器)的其他資源。
Blocked -- 鎖阻塞
當(dāng)一個(gè)線程想獲取一個(gè)對(duì)象鎖,不過該對(duì)象鎖被其它的線程持有時(shí),該線程就會(huì)進(jìn)入鎖阻塞狀態(tài);當(dāng)該線程持有鎖的時(shí)候,該線程將會(huì)變成可運(yùn)行的狀態(tài)。
Waiting -- 無限等待
當(dāng)一個(gè)線程在等待另一個(gè)線程執(zhí)行一個(gè)(喚醒)動(dòng)作時(shí),該線程就會(huì)進(jìn)入無限等待狀態(tài)。進(jìn)入這個(gè)狀態(tài)后是不能自動(dòng)喚醒的,要等待另一個(gè)線程調(diào)用notify()方法,或notifyall()方法才能夠被喚醒。
Timed_Waiting -- 計(jì)時(shí)等待
類似于無限等待狀態(tài),有幾個(gè)方法有超時(shí)參數(shù),如:Thread.sleep、Object.wait方法。調(diào)用這些方法,進(jìn)入計(jì)時(shí)等待狀態(tài)。計(jì)時(shí)等待狀態(tài)將會(huì)一直保持到超時(shí)期滿或者接收到喚醒通知。
terminated -- 被終止
1、因?yàn)閞un方法的正常退出而死亡。
2、因?yàn)闆]有捕獲的異常,終止了run方法而死亡。
等待喚醒案例切入
顧客要去飯店吃飯,自助下單,說明要吃什么,數(shù)量是多少。下完單以后,顧客就等待該飯店廚師做飯菜,也就是Waiting狀態(tài)(無限等待狀態(tài))。
廚師收到下單信息,開始做飯菜,做好飯菜,把飯菜遞到顧客桌面上,顧客看到飯菜已經(jīng)來了(notify方法),就可以開吃了(等待喚醒機(jī)制)。
Java代碼實(shí)現(xiàn)(線程之間的通信)
分析
創(chuàng)建一個(gè)顧客線程:下單,告知廚師要什么菜,菜的數(shù)量,調(diào)用wait方法,放棄CPU的執(zhí)行,進(jìn)入到無限等待狀態(tài)(Waiting)
創(chuàng)建一個(gè)廚師線程:看到下單,花了3秒鐘做飯菜,做好之后,調(diào)用notify方法,喚醒顧客吃飯了。
注意
顧客線程和廚師線程,必須使用同步代碼塊包裹起來,保證等待和喚醒只能有一個(gè)在執(zhí)行。
同步使用的鎖對(duì)象必須保證唯一。
只有鎖對(duì)象才能夠調(diào)用Object.wait方法和Object.notify方法。
代碼
public class Demo01WaitNotify { public static void main(String[] args) { // 創(chuàng)建鎖對(duì)象(要保證鎖唯一) Object object = new Object(); // 創(chuàng)建一個(gè)顧客線程 new Thread() { @Override public void run() { // 使用同步代碼塊包裹起來,保證等待和喚醒只能有一個(gè)在執(zhí)行。 synchronized (object) { // 顧客下單 System.out.println("我要一個(gè)西虹市炒番茄,一個(gè)馬鈴薯炒土豆,兩碗米飯"); // 調(diào)用wait方法,放棄CPU的執(zhí)行,進(jìn)入到無限等待狀態(tài)(Waiting) try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } // 喚醒之后(飯菜上來后),吃飯!?。≌嫦?。 System.out.println("我就是餓死,從這里跳下去,也不會(huì)吃你們一口飯。。。真香!?。?!"); } } }.start(); // 創(chuàng)建一個(gè)廚師線程 new Thread() { @Override public void run() { // 廚師收到下單請(qǐng)求,花三秒鐘把飯菜做好 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // 使用同步代碼塊包裹起來,保證等待和喚醒只能有一個(gè)在執(zhí)行。 synchronized (object) { System.out.println("我的飯菜三秒鐘做好了,你食唔食哦?"); // 做好之后,調(diào)用notify方法,喚醒顧客吃飯了。 object.notify(); } } }.start(); } }
控制臺(tái)輸出:
我要一個(gè)西虹市炒番茄,一個(gè)馬鈴薯炒土豆,兩碗米飯
我的飯菜三秒鐘做好了,你食唔食哦?
我就是餓死,從這里跳下去,也不會(huì)吃你們一口飯。。。真香?。。?!
上面的代碼,存在線程間的通信,那什么又是線程間的通信呢?簡(jiǎn)單的說,就是多個(gè)線程在處理同一個(gè)資源,但是處理的動(dòng)作(線程的任務(wù))卻不同。如上,廚師線程做飯菜,顧客線程吃飯菜。那為什么要進(jìn)行線程間的通信呢?多個(gè)線程并發(fā)執(zhí)行的時(shí)候,在默認(rèn)情況下CPU是隨機(jī)切換線程的,當(dāng)我們需要多個(gè)線程來共同完成一件任務(wù),并且希望它們有規(guī)律的執(zhí)行的時(shí)候,那么多線程就之間就需要一些協(xié)調(diào)通信,來達(dá)到多線程共同操作一份數(shù)據(jù)。
對(duì)代碼中通信的理解:
對(duì)又沒有飯菜進(jìn)行判斷——
1、沒有飯菜(False)。
2、顧客下單。
3、廚師做飯菜。
4、顧客線程等待。
5、廚師做好飯菜
6、修改飯菜的狀態(tài)(True)
7、有飯菜,廚師線程提醒顧客線程吃飯菜。
8、廚師線程等待
9、吃完飯菜,修改飯菜的狀態(tài)(False)
這就是顧客線程與廚師線程之間的通信。以此類推,其它Java程序中多線程的通信也是同樣的道理。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot Knife4j在線API文檔框架基本使用
knife4j是為Java MVC框架集成Swagger生成Api文檔的增強(qiáng)解決方案,這篇文章主要介紹了SpringBoot中使用Knife4J在線API文檔框架,需要的朋友可以參考下2022-12-12Java實(shí)現(xiàn)Excel文件轉(zhuǎn)PDF(無水印無限制)
這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)Excel文件轉(zhuǎn)PDF的效果,并可以無水印、無限制。文中的示例代碼講解詳細(xì),需要的可以參考一下2022-06-06Java數(shù)據(jù)結(jié)構(gòu)和算法之冒泡排序(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)
冒泡排序(Bubble Sort)是一種簡(jiǎn)單的排序算法。本文重點(diǎn)給大家介紹java數(shù)據(jù)結(jié)構(gòu)和算法之冒泡排序,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-04-04Java的設(shè)計(jì)模式編程中迪米特法則的應(yīng)用示例
這篇文章主要介紹了Java的設(shè)計(jì)模式編程中迪米特法則的應(yīng)用示例,迪米特法則中主張創(chuàng)建和使用弱耦合的類,需要的朋友可以參考下2016-02-02Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼,歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個(gè)非常典型的應(yīng)用,將已有序的子序列合并,得到完全有序的序列,需要的朋友可以參考下2023-10-10