java多線程編程學(xué)習(xí)(線程間通信)
一、概要
二、等待/通知機(jī)制
1、"wait/notify"機(jī)制:等待/通知機(jī)制,wait使線程暫停運(yùn)行,而notify 使暫停的線程繼續(xù)運(yùn)行。用一個(gè)廚師和服務(wù)員的交互來說明:
(1) 服務(wù)員取到菜的時(shí)間取決于廚師,所以服務(wù)員就有“等待”(wait)的狀態(tài)。
(2) 廚師將菜放在“菜品傳遞臺(tái)”上,其實(shí)就相當(dāng)于一種通知(notify),這時(shí)服務(wù)員才可以拿到菜并交給就餐者。
2、wait()
(1) 使當(dāng)前執(zhí)行代碼的線程進(jìn)行等待。wait()方法是Object類的方法,該方法用來將當(dāng)前線程置入“預(yù)執(zhí)行隊(duì)列”中,并且在wait()所在的代碼行處停止執(zhí)行,直到接收通知或被中斷為止。
(2) 在調(diào)用wait()方法之前,線程必須獲得該對(duì)象的對(duì)象級(jí)別鎖,即只能在同步方法或同步塊中調(diào)用wait()方法,否則拋出IllegalMonitorStateException異常。(屬于Runtime的一個(gè)子類,不需要try-catch 語(yǔ)句進(jìn)行捕捉異常)
(3) 在調(diào)用wait()方法之后,當(dāng)前線程釋放鎖,而此對(duì)象會(huì)進(jìn)入線程等待池中,等待被喚醒。在從wait()返回前,線程與其他呈wait線程競(jìng)爭(zhēng)重新獲得鎖。
(4) wait()方法可以被interrupt 打斷并拋出InterruptedException。
(5) wait(long):帶一個(gè)參數(shù)的wait(long)方法的功能是等待某一時(shí)間內(nèi)是否有線程對(duì)鎖進(jìn)行喚醒,如果超過這個(gè)時(shí)間則自動(dòng)喚醒。
3、notify()
(1) 用來通知那些可能等待該對(duì)象的對(duì)象鎖的其他線程。如果有多個(gè)線程等待,則由線程規(guī)劃器隨機(jī)挑選出其中一個(gè)呈wait狀態(tài)的線程,對(duì)其發(fā)出通知notify,并使它等待獲取該對(duì)象的對(duì)象鎖。(注意!這里說的是等待,即在執(zhí)行完notify()方法后,當(dāng)前線程不會(huì)馬上釋放該對(duì)象鎖,即wait()狀態(tài)的線程也不會(huì)馬上獲得對(duì)象鎖,需要將synchronized 代碼塊中的代碼執(zhí)行完后才釋放鎖!)
(2)也要在同步方法或同步塊中調(diào)用,即在調(diào)用前,線程也必須獲得該對(duì)象的對(duì)象級(jí)別鎖,否則也會(huì)拋出IllegalMonitorStateException.
(3)當(dāng)notify()發(fā)出通知,卻沒有wait()線程在等待時(shí),則不作作用。
4、notifyAll()
5、
6、假死:“假死”現(xiàn)象其實(shí)就是線程進(jìn)入WAITING等待狀態(tài)。如果全部線程都進(jìn)入WAITING狀態(tài),則程序就不再執(zhí)行任何功能了,整個(gè)項(xiàng)目呈停止?fàn)顟B(tài)。 出現(xiàn)這樣的原因是因?yàn)椋罕热缍鄠€(gè)生產(chǎn)者和多個(gè)消費(fèi)者的問題,“生產(chǎn)者”可能喚醒“生產(chǎn)者”,“消費(fèi)者”可能喚醒“消費(fèi)者”,喚醒了同類,導(dǎo)致線程不斷在等待。怎么解決這個(gè)問題呢?將notify() 改成 notifyAll()方法即可,也就是將異類一同喚醒就可以了。
7、 Jave中 管道流(pipeStream)是一種特殊的流,可用于在不同的線程中直接傳送數(shù)據(jù)。一個(gè)線程發(fā)送數(shù)據(jù)到輸出管道,另一個(gè)線程從輸入管道中讀數(shù)據(jù)。通過使用管道,實(shí)現(xiàn)不同線程間的通信,而無(wú)須借助于類似臨時(shí)文件之類的東西。JDK中提供了四個(gè)類來使線程間可以通信,其中包括字節(jié)流(PipedOutputStream、PipedInputStream)和字符流(PipedWriter、PipedReader)。
public class Run { public static void main(String[] args) { try { WriteData writeData = new WriteData(); ReadData readData = new ReadData(); PipedOutputStream outputStream = new PipedOutputStream(); PipedInputStream inputStream = new PipedInputStream(); outputStream.connect(inputStream);//使兩個(gè)Stream之間產(chǎn)生通信鏈接,這樣才可以將數(shù)據(jù)進(jìn)行輸入輸出 ThreadRead threadRead = new ThreadRead(readData, inputStream); threadRead.start(); Thread.sleep(1000); ThreadWrite threadWrite = new ThreadWrite(writeData, outputStream); threadWrite.start(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
三、方法join的使用
1、在很多情況下,主線程創(chuàng)建并啟動(dòng)子線程,如果子線程中要進(jìn)行大量的耗時(shí)計(jì)算,主線程往往將早于子線程結(jié)束之前結(jié)束。這時(shí),如果主線程想等待子線程執(zhí)行完成之后再結(jié)束,比如子線程處理一個(gè)數(shù)據(jù),主線程要取得這個(gè)數(shù)據(jù)中的值,就要用到j(luò)oin()方法了。
2、join()的作用是等待線程銷毀,而使 當(dāng)前線程進(jìn)行無(wú)限期的阻塞,等待join()的線程銷毀后再繼續(xù)執(zhí)行當(dāng)前線程的代碼。
3、同樣的,join()方法可以被interrupt()方法打斷并拋出InterruptedException異常。
4、join 與 synchronized 的區(qū)別?
(1) join()在內(nèi)部使用wait() 方法進(jìn)行等待。
(2) synchronized 關(guān)鍵字使用的是“對(duì)象監(jiān)視器”原理作為同步。
5、方法join(long) 和 sleep(long)的區(qū)別?
(1) join(long)內(nèi)部采用wait(long)方法實(shí)現(xiàn),當(dāng)執(zhí)行wait(long)方法后,當(dāng)前線程的鎖被釋放,那么其他線程也可以調(diào)用此線程中的同步方法了。即 join(long)之后,該線程釋放鎖,又需要和其他線程去爭(zhēng)搶鎖的資源。
(2) Thread.sleep(long)方法不釋放鎖。
四、類 ThreadLocal 的使用
1、變量值的共享可以使用public static 變量的形式,所有的線程都使用同一個(gè)public static 變量。如果想實(shí)現(xiàn)每一個(gè)線程都有自己的共享變量該如何解決呢?類ThreadLocal解決的就是每個(gè)線程綁定自己的值,可以將ThreadLocal類比喻成全局存放數(shù)據(jù)的盒子,盒子中可以存放每個(gè)線程的私有數(shù)據(jù)。
2、類ThreadLocal 具有隔離性,即每個(gè)線程都可以存入自己線程的數(shù)據(jù)而互不影響,而取到的也是自己線程存入的數(shù)據(jù)。
五、類InheritableThreadLocal的使用
1、InheritableThreadLocal類繼承于ThreadLocal類,所以它具有ThreadLocal類的特性,但又是一種特殊的ThreadLocal,其特殊性在于InheritableThreadLocal變量值會(huì)自動(dòng)傳遞給所有子線程,而普通ThreadLocal變量不行;而且,通過重寫這個(gè)類中的 childValue 方法,子線程的值可以作為父線程值的一個(gè)任意函數(shù)。
備注:
(1) 什么是子線程?
包含在 Thread thread = new Thread(new ThreadStart(delegate{
}));里面均視為子線程。(個(gè)人理解)
(2) 什么是主線程?
UI界面和Main函數(shù)均為主線程,除了“不包含在Thread里面的程序”均可 視為主線程。(個(gè)人理解)
以上這篇java多線程編程學(xué)習(xí)(線程間通信)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java的作業(yè)調(diào)度類庫(kù)Quartz基本使用指南
這篇文章主要介紹了Java的作業(yè)調(diào)度類庫(kù)Quartz基本使用指南,Quartz能夠讓類按照指定的計(jì)劃順序執(zhí)行,需要的朋友可以參考下2016-03-03springboot項(xiàng)目實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能
這篇文章主要介紹了springboot項(xiàng)目實(shí)現(xiàn)斷點(diǎn)續(xù)傳,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08Java在Word中插入上標(biāo)和下標(biāo)的實(shí)現(xiàn)方法
在某些情況下,你可能需要在Microsoft?Word中插入上標(biāo)和下標(biāo)。例如,當(dāng)你正在創(chuàng)建一個(gè)涉及科學(xué)公式的學(xué)術(shù)文件時(shí),在這篇文章中,你將學(xué)習(xí)如何使用Spire.Doc?for?Java庫(kù)在Word文檔中插入上標(biāo)和下標(biāo),需要的朋友可以參考下2022-10-10SpringBoot監(jiān)控Tomcat活動(dòng)線程數(shù)來判斷是否完成請(qǐng)求處理方式
這篇文章主要介紹了SpringBoot監(jiān)控Tomcat活動(dòng)線程數(shù)來判斷是否完成請(qǐng)求處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Java數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹的原理與實(shí)現(xiàn)
平衡樹(Balance Tree,BT) 指的是,任意節(jié)點(diǎn)的子樹的高度差都小于等于1。常見的符合平衡樹的有,B樹(多路平衡搜索樹)、AVL樹(二叉平衡搜索樹)等。本文將詳細(xì)介紹平衡二叉樹的概念和實(shí)現(xiàn)原理以及它的實(shí)現(xiàn)2022-01-01SpringBoot整合dataworks的實(shí)現(xiàn)過程
這篇文章主要介紹了SpringBoot整合dataworks的實(shí)現(xiàn)過程,實(shí)現(xiàn)主要是編寫工具類,如果需要?jiǎng)t可以配置成SpringBean,注入容器即可使用,需要的朋友可以參考下2022-08-08SpringBoot集成ActiveMQ的實(shí)戰(zhàn)全過程
消息隊(duì)列中間件是分布式系統(tǒng)中重要的組件,主要解決應(yīng)用耦合、異步消息、流量削鋒等問題,實(shí)現(xiàn)高性能、高可用、可伸縮和最終一致性架構(gòu),是大型分布式系統(tǒng)不可缺少的中間件,這篇文章主要給大家介紹了關(guān)于SpringBoot集成ActiveMQ的相關(guān)資料,需要的朋友可以參考下2021-11-11