淺談Java線程間通信方式
線程間通信方式有兩種:共享內(nèi)存和消息傳遞。
不同進(jìn)程間線程通信等同于進(jìn)程間通信,同一進(jìn)程間可用共享內(nèi)存實(shí)現(xiàn)。
在共享內(nèi)存的并發(fā)模型里,線程之間共享程序的公共狀態(tài),線程之間通過寫-讀內(nèi)存中的公共狀態(tài)來隱式進(jìn)行通信,典型的共享內(nèi)存通信方式就是通過共享對(duì)象進(jìn)行通信。
在消息傳遞的并發(fā)模型里,線程之間沒有公共狀態(tài),線程之間必須通過明確的發(fā)送消息來顯式進(jìn)行通信,在java中典型的消息傳遞方式就是wait()和notify()。
詳細(xì)來說,線程通信有以下幾種方式:
1.volatile和synchronized關(guān)鍵字
volatile關(guān)鍵字保證了共享變量的可見性,任何線程需要讀取時(shí)都要到內(nèi)存中讀取(確保獲得最新值)。synchronized關(guān)鍵字確保只能同時(shí)有一個(gè)線程訪問方法或者變量,保證了線程訪問的可見性和排他性。
synchronized底層是基于監(jiān)視器(Monitor)的獲取,每個(gè)對(duì)象都有自己的監(jiān)視器,線程必須獲得監(jiān)視器才能繼續(xù)執(zhí)行內(nèi)容。
2.等待/通知機(jī)制
等待/通知機(jī)制,是指一個(gè)線程A調(diào)用了對(duì)象O的wait()方法進(jìn)入等待狀態(tài),而另一個(gè)線程B 調(diào)用了對(duì)象O的notify()或者notifyAll()方法,線程A收到通知后從對(duì)象O的wait()方法返回,進(jìn)而 執(zhí)行后續(xù)操作。上述兩個(gè)線程通過對(duì)象O來完成交互,而對(duì)象上的wait()和notify/notifyAll()的 關(guān)系就如同開關(guān)信號(hào)一樣,用來完成等待方和通知方之間的交互工作(注意此機(jī)制要和鎖一起使用,調(diào)用notify的線程執(zhí)行完后釋放了鎖新喚醒線程才能運(yùn)行)。
3.管道輸入/輸出流
管道輸入/輸出流和普通的文件輸入/輸出流或者網(wǎng)絡(luò)輸入/輸出流不同之處在于,它主要 用于線程之間的數(shù)據(jù)傳輸,而傳輸?shù)拿浇闉閮?nèi)存。
管道輸入/輸出流主要包括了如下4種具體實(shí)現(xiàn):PipedOutputStream
、PipedInputStream
、 PipedReader
和PipedWriter
,前兩種面向字節(jié),而后兩種面向字符。
public class Piped { public static void main(String[] args) throws Exception { PipedWriter out = new PipedWriter(); PipedReader in = new PipedReader(); // 將輸出流和輸入流進(jìn)行連接,否則在使用時(shí)會(huì)拋出IOException out.connect(in); Thread printThread = new Thread(new Print(in), "PrintThread"); printThread.start(); int receive = 0; try { while ((receive = System.in.read()) != -1) { out.write(receive); } } finally { out.close(); } } static class Print implements Runnable { private PipedReader in; public Print(PipedReader in) { this.in = in; } public void run() { int receive = 0; try { while ((receive = in.read()) != -1) { System.out.print((char) receive); } } catch (IOException ex) { } } } }
4.join()方法
如果一個(gè)線程A執(zhí)行了thread.join()語句,其含義是:當(dāng)前線程A等待thread線程終止之后才 從thread.join()返回。線程Thread除了提供join()方法之外,還提供了join(long millis)和join(long millis,int nanos)兩個(gè)具備超時(shí)特性的方法。這兩個(gè)超時(shí)方法表示,如果線程thread在給定的超時(shí) 時(shí)間里沒有終止,那么將會(huì)從該超時(shí)方法中返回。
每個(gè)線程終止的前提是前驅(qū)線程的終止,每個(gè)線程等待前驅(qū)線程終止后,才從join()方法返回,這里涉及了等待/通知機(jī)制(等待前驅(qū)線程結(jié)束,接收前驅(qū)線程結(jié)束通知)。
5.ThreadLocal()方法
ThreadLocal,即線程本地變量(每個(gè)線程都有自己唯一的一個(gè)哦),是一個(gè)以ThreadLocal對(duì)象為鍵、任意對(duì)象為值的存儲(chǔ)結(jié)構(gòu)。底層是一個(gè)ThreadLocalMap來存儲(chǔ)信息,key是弱引用,value是強(qiáng)引用,所以使用完畢后要及時(shí)清理(尤其使用線程池時(shí))。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringBoot部署在tomcat容器中運(yùn)行的部署方法
這篇文章主要介紹了SpringBoot部署在tomcat容器中運(yùn)行的部署方法,需要的朋友可以參考下2018-10-10RocketMQ重試機(jī)制及消息冪代碼實(shí)例解析
這篇文章主要介紹了RocketMQ重試機(jī)制及消息冪代碼實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02ServletWebServerApplicationContext創(chuàng)建Web容器Tomcat示例
這篇文章主要為大家介紹了ServletWebServerApplicationContext創(chuàng)建Web容器Tomcat示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03構(gòu)建springboot自動(dòng)生成mapper文件和dao接口項(xiàng)目的步驟和配置方法
這篇文章主要介紹了構(gòu)建springboot自動(dòng)生成mapper文件和dao接口項(xiàng)目的步驟和配置方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05Java安全之Tomcat6 Filter內(nèi)存馬問題
這篇文章主要介紹了Java安全之Tomcat6 Filter內(nèi)存馬,通過本文探討下Tomcat6與Tomcat8之間的區(qū)別,主要看下tomcat6和tomcat8之間createFilterChain不相同的地方 看到ApplicationFilterFactory#createFilterChain,需要的朋友可以參考下2022-10-10Java Web使用簡單的批處理操作(記事本+Tomcat)
這篇文章主要介紹了Java Web使用簡單的批處理操作 ,需要的朋友可以參考下2014-10-10