本篇文章給大家分享的是有關(guān)Java中等待喚醒機(jī)制線程通信的原理是什么,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
成都創(chuàng)新互聯(lián)長(zhǎng)期為上1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為文成企業(yè)提供專業(yè)的成都網(wǎng)站制作、成都做網(wǎng)站,文成網(wǎng)站改版等技術(shù)服務(wù)。擁有十載豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
線程間通信
概念:多個(gè)線程在處理同一個(gè)資源,但是處理的動(dòng)作(線程的任務(wù))卻不相同。比如:線程A用來(lái)生成包子的,線程B用來(lái)吃包子的,包子可以理解為同一資源,線程A與線程B處理的動(dòng)作,一個(gè)是生產(chǎn),一個(gè)是消費(fèi),那么線程A與線程B之間就存在線程通信問(wèn)題。

為什么要處理線程間通信:
多個(gè)線程并發(fā)執(zhí)行時(shí), 在默認(rèn)情況下CPU是隨機(jī)切換線程的,當(dāng)我們需要多個(gè)線程來(lái)共同完成一件任務(wù),并且我們希望他們有規(guī)律的執(zhí)行, 那么多線程之間需要一些協(xié)調(diào)通信,以此來(lái)幫我們達(dá)到多線程共同操作一份數(shù)據(jù)。
如何保證線程間通信有效利用資源:
多個(gè)線程在處理同一個(gè)資源,并且任務(wù)不同時(shí),需要線程通信來(lái)幫助解決線程之間對(duì)同一個(gè)變量的使用或操作。 就是多個(gè)線程在操作同一份數(shù)據(jù)時(shí), 避免對(duì)同一共享變量的爭(zhēng)奪。也就是我們需要通過(guò)一定的手段使各個(gè)線程能有效的利用資源。而這種手段即—— 等待喚醒機(jī)制。
等待喚醒機(jī)制
什么是等待喚醒機(jī)制
這是多個(gè)線程間的一種協(xié)作機(jī)制。談到線程我們經(jīng)常想到的是線程間的競(jìng)爭(zhēng)(race),比如去爭(zhēng)奪鎖,但這并不是故事的全部,線程間也會(huì)有協(xié)作機(jī)制。就好比在公司里你和你的同事們,你們可能存在在晉升時(shí)的競(jìng)爭(zhēng),但更多時(shí)候你們更多是一起合作以完成某些任務(wù)。就是在一個(gè)線程進(jìn)行了規(guī)定操作后,就進(jìn)入等待狀態(tài)(wait()), 等待其他線程執(zhí)行完他們的指定代碼過(guò)后 再將其喚醒(notify());在有多個(gè)線程進(jìn)行等待時(shí), 如果需要,可以使用 notifyAll()來(lái)喚醒所有的等待線程。wait/notify 就是線程間的一種協(xié)作機(jī)制。
等待喚醒中的方法
等待喚醒機(jī)制就是用于解決線程間通信的問(wèn)題的,使用到的3個(gè)方法的含義如下:
wait:線程不再活動(dòng),不再參與調(diào)度,進(jìn)入 wait set 中,因此不會(huì)浪費(fèi) CPU 資源,也不會(huì)去競(jìng)爭(zhēng)鎖了,這時(shí)的線程狀態(tài)即是 WAITING。它還要等著別的線程執(zhí)行一個(gè)特別的動(dòng)作,也即是“通知(notify)”在這個(gè)對(duì)象上等待的線程從wait set 中釋放出來(lái),重新進(jìn)入到調(diào)度隊(duì)列(ready queue)中
notify:則選取所通知對(duì)象的 wait set 中的一個(gè)線程釋放;例如,餐館有空位置后,等候就餐最久的顧客最先入座。
notifyAll:則釋放所通知對(duì)象的 wait set 上的全部線程。
注意:
哪怕只通知了一個(gè)等待的線程,被通知線程也不能立即恢復(fù)執(zhí)行,因?yàn)樗?dāng)初中斷的地方是在同步塊內(nèi),而此刻它已經(jīng)不持有鎖,所以她需要再次嘗試去獲取鎖(很可能面臨其它線程的競(jìng)爭(zhēng)),成功后才能在當(dāng)初調(diào)用 wait 方法之后的地方恢復(fù)執(zhí)行。
總結(jié)如下:
如果能獲取鎖,線程就從 WAITING 狀態(tài)變成 RUNNABLE 狀態(tài);否則,從 wait set 出來(lái),又進(jìn)入 entry set,線程就從 WAITING 狀態(tài)又變成 BLOCKED 狀態(tài)調(diào)用wait和notify方法需要注意的細(xì)節(jié)
wait方法與notify方法必須要由同一個(gè)鎖對(duì)象調(diào)用。因?yàn)椋簩?duì)應(yīng)的鎖對(duì)象可以通過(guò)notify喚醒使用同一個(gè)鎖對(duì)象調(diào)用的wait方法后的線程。
wait方法與notify方法是屬于Object類的方法的。因?yàn)椋烘i對(duì)象可以是任意對(duì)象,而任意對(duì)象的所屬類都是繼承了Object類的。
wait方法與notify方法必須要在同步代碼塊或者是同步函數(shù)中使用。因?yàn)椋罕仨氁ㄟ^(guò)鎖對(duì)象調(diào)用這2個(gè)方法。
生產(chǎn)者與消費(fèi)者問(wèn)題
等待喚醒機(jī)制其實(shí)就是經(jīng)典的“生產(chǎn)者與消費(fèi)者”的問(wèn)題。就拿生產(chǎn)包子消費(fèi)包子來(lái)說(shuō)等待喚醒機(jī)制如何有效利用資源:
/* 包子鋪線程生產(chǎn)包子,吃貨線程消費(fèi)包子。當(dāng)包子沒(méi)有時(shí)(包子狀態(tài)為false),吃貨線程等待,包子鋪線程生產(chǎn)包子 (即包子狀態(tài)為true),并通知吃貨線程(解除吃貨的等待狀態(tài)),因?yàn)橐呀?jīng)有包子了,那么包子鋪線程進(jìn)入等待狀態(tài)。 接下來(lái),吃貨線程能否進(jìn)一步執(zhí)行則取決于鎖的獲取情況。如果吃貨獲取到鎖,那么就執(zhí)行吃包子動(dòng)作,包子吃完(包 子狀態(tài)為false),并通知包子鋪線程(解除包子鋪的等待狀態(tài)),吃貨線程進(jìn)入等待。包子鋪線程能否進(jìn)一步執(zhí)行則取 決于鎖的獲取情況 */
代碼實(shí)現(xiàn)
包子類
package demo01;
public class BaoZi {
String pier;
String xianer;
boolean flag = false;//包子資源 是否存在 包子資源狀態(tài)
}吃貨線程類:
package demo01;
public class ChiHuo extends Thread {
private BaoZi bz;
public ChiHuo(String name, BaoZi bz) {
super(name);
this.bz = bz;
}
@Override
public void run() {
while (true) {
synchronized (bz) {
if (bz.flag == false) {//沒(méi)包子
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("吃貨正在吃" + bz.pier + bz.xianer + "包子");
bz.flag = false;
bz.notify();
}
}
}
}包子鋪線程類:
package demo01;
public class BaoZiPu extends Thread {
private BaoZi bz;
public BaoZiPu(String name, BaoZi bz) {
super(name);
this.bz = bz;
}
@Override
public void run() {
int count = 0;
//造包子
while (true) {
//同步
synchronized (bz) {
if (bz.flag == true) {//包子資源 存在
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 沒(méi)有包子 造包子
System.out.println("包子鋪開始做包子");
if (count % 2 == 0) {
// 冰皮 五仁
bz.pier = "冰皮";
bz.xianer = "五仁";
} else {
// 薄皮 牛肉大蔥
bz.pier = "薄皮";
bz.xianer = "牛肉大蔥";
}
count++;
bz.flag = true;
System.out.println("包子造好了:" + bz.pier + bz.xianer);
System.out.println("吃貨來(lái)吃吧");
//喚醒等待線程 (吃貨)
bz.notify();
}
}
}
}測(cè)試類:
package demo01;
public class Demo {
public static void main(String[] args) {
//等待喚醒案例
BaoZi bz = new BaoZi();
ChiHuo ch = new ChiHuo("吃貨",bz);
BaoZiPu bzp = new BaoZiPu("包子鋪",bz);
ch.start();
bzp.start();
}
}以上就是Java中等待喚醒機(jī)制線程通信的原理是什么,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享標(biāo)題:Java中等待喚醒機(jī)制線程通信的原理是什么
瀏覽地址:http://www.chinadenli.net/article28/ipphcp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、關(guān)鍵詞優(yōu)化、小程序開發(fā)、標(biāo)簽優(yōu)化、靜態(tài)網(wǎng)站、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)