Java線程通信的幾種方式

一、問題

有兩個線程,A 線程向一個集合里面依次添加元素“abc”字符串,一共添加十次,當添加到第五次的時候,希望 B 線程能夠收到 A 線程的通知,然后 B 線程執行相關的業務操作。線程間通信的模型有兩種:共享內存和消息傳遞,以下方式都是基本這兩種模型來實現的。

二、使用 volatile 關鍵字

基于 volatile 關鍵字來實現線程間相互通信是使用共享內存的思想。大致意思就是多個線程同時監聽一個變量,當這個變量發生變化的時候 ,線程能夠感知并執行相應的業務。這也是最簡單的一種實現方式

public class TestSync {//定義共享變量來實現通信,它需要volatile修飾,否則線程不能及時感知static volatile boolean notice = false;public static void main(String[] args) {List<String>  list = new ArrayList<>();//線程AThread threadA = new Thread(() -> {for (int i = 1; i <= 10; i++) {list.add("abc");System.out.println("線程A添加元素,此時list的size為:" + list.size());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (list.size() == 5)notice = true;}});//線程BThread threadB = new Thread(() -> {while (true) {if (notice) {System.out.println("線程B收到通知,開始執行自己的業務...");break;}}});//需要先啟動線程BthreadB.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 再啟動線程AthreadA.start();}
}

三、使用 Object 類的 wait()/notify()

Object 類提供了線程間通信的方法:wait()、notify()、notifyAll(),它們是多線程通信的基礎,而這種實現方式的思想自然是線程間通信。

注意: wait/notify 必須配合 synchronized 使用,wait 方法釋放鎖,notify 方法不釋放鎖。wait 是指在一個已經進入了同步鎖的線程內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖并運行,只有其他線程調用了notify()notify并不釋放鎖,只是告訴調用過wait()的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手里,別人還沒釋放,調用 wait() 的一個或多個線程就會解除 wait 狀態,重新參與競爭對象鎖,程序如果可以再次得到鎖,就可以繼續向下運行。

public class TestSync {public static void main(String[] args) {//定義一個鎖對象Object lock = new Object();List<String>  list = new ArrayList<>();// 線程AThread threadA = new Thread(() -> {synchronized (lock) {for (int i = 1; i <= 10; i++) {list.add("abc");System.out.println("線程A添加元素,此時list的size為:" + list.size());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (list.size() == 5)lock.notify();//喚醒B線程}}});//線程BThread threadB = new Thread(() -> {while (true) {synchronized (lock) {if (list.size() != 5) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("線程B收到通知,開始執行自己的業務...");}}});//需要先啟動線程BthreadB.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//再啟動線程AthreadA.start();}
}

由輸出結果,在線程 A 發出 notify() 喚醒通知之后,依然是走完了自己線程的業務之后,線程 B 才開始執行,正好說明 notify() 不釋放鎖,而 wait() 釋放鎖。

四、使用JUC工具類 CountDownLatch

jdk1.5 之后在java.util.concurrent包下提供了很多并發編程相關的工具類,簡化了并發編程代碼的書寫,CountDownLatch 基于 AQS 框架,相當于也是維護了一個線程間共享變量 state。

public class TestSync {public static void main(String[] args) {CountDownLatch countDownLatch = new CountDownLatch(1);List<String>  list = new ArrayList<>();//線程AThread threadA = new Thread(() -> {for (int i = 1; i <= 10; i++) {list.add("abc");System.out.println("線程A添加元素,此時list的size為:" + list.size());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (list.size() == 5)countDownLatch.countDown();}});//線程BThread threadB = new Thread(() -> {while (true) {if (list.size() != 5) {try {countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("線程B收到通知,開始執行自己的業務...");break;}});//需要先啟動線程BthreadB.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//再啟動線程AthreadA.start();}
}

五、使用 ReentrantLock 結合 Condition

public class TestSync {public static void main(String[] args) {ReentrantLock lock = new ReentrantLock();Condition condition = lock.newCondition();List<String> list = new ArrayList<>();//線程AThread threadA = new Thread(() -> {lock.lock();for (int i = 1; i <= 10; i++) {list.add("abc");System.out.println("線程A添加元素,此時list的size為:" + list.size());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (list.size() == 5)condition.signal();}lock.unlock();});//線程BThread threadB = new Thread(() -> {lock.lock();if (list.size() != 5) {try {condition.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("線程B收到通知,開始執行自己的業務...");lock.unlock();});threadB.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}threadA.start();}
}

這種方式使用起來并不是很好,代碼編寫復雜,而且線程 B 在被 A 喚醒之后由于沒有獲取鎖還是不能立即執行,也就是說,A 在喚醒操作之后,并不釋放鎖。這種方法跟 Object 的 wait()/notify() 一樣。

六、基本 LockSupport 實現線程間的阻塞和喚醒

LockSupport 是一種非常靈活的實現線程間阻塞和喚醒的工具,使用它不用關注是等待線程先進行還是喚醒線程先運行,但是得知道線程的名字。

public class TestSync {public static void main(String[] args) {List<String> list = new ArrayList<>();//線程Bfinal Thread threadB = new Thread(() -> {if (list.size() != 5) {LockSupport.park();}System.out.println("線程B收到通知,開始執行自己的業務...");});//線程AThread threadA = new Thread(() -> {for (int i = 1; i <= 10; i++) {list.add("abc");System.out.println("線程A添加元素,此時list的size為:" + list.size());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}if (list.size() == 5)LockSupport.unpark(threadB);}});threadA.start();threadB.start();}
}


---------------------
作者:一起努力啊啊啊啊
來源:CSDN
原文:https://blog.csdn.net/ChineseSoftware/article/details/118390388
版權聲明:本文為作者原創文章,轉載請附上博文鏈接!
內容解析By:CSDN,CNBLOG博客文章一鍵轉載插件

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

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

相關文章

PHP個人博客項目------切切歆語博客

2019獨角獸企業重金招聘Python工程師標準>>> phpmysqlapache, ThinkPHP3.2框架開發 我的個人博客項目 適合新手練習 源碼地址下載&#xff1a;https://github.com/DickyQie/php-myblog 轉載于:https://my.oschina.net/zhangqie/blog/1785867

收發郵件之 MAILKIT

背景利用代碼發送郵件在工作中還是比較常見的&#xff0c;相信大家都用過SmtpClient來處理發送郵件的操作&#xff0c;不過這個類以及被標記已過時&#xff0c;所以介紹一個微軟推薦的庫MailKit來處理。MailKit開源地址&#xff1a;https://github.com/jstedfast/MailKit需要郵…

IOS_SearchBar搜索欄及關鍵字高亮

搜索框的效果演示: 這個就是所謂的搜索框了,那么接下來我們看看如何使用代碼來實現這個功能. 我所使用的數據是英雄聯盟的英雄名單,是一個JSON數據的txt文件, JSON數據的處理代碼如下所示: ?123456//獲取文件的路徑pathNSString *path [[NSBundle mainBundle] pathForResourc…

Java設計模式之(工廠模式)--簡單工廠模式--工廠方法模式--抽象工廠模式

工廠模式&#xff1a; 工廠模式可以分為三類&#xff1a; 1&#xff09;簡單工廠模式&#xff08;Simple Factory&#xff09; 2&#xff09;工廠方法模式&#xff08;Factory Method&#xff09; 3&#xff09;抽象工廠模式&#xff08;Abstract Factory&#xff09; 簡單工…

今天很多 CTO 都是被干掉的,因為他沒有成就業務

作者&#xff5c;喬新亮 編輯&#xff5c;鄧艷琴 我可以絲毫不開玩笑地說&#xff0c;今天&#xff0c;很多傳統企業里的研發都只是“工人”&#xff0c;哪怕是 CTO&#xff0c;充其量也只是“高級工人”&#xff0c;如果不轉換思維去成就業務&#xff0c;就只能停留在工人級…

中航工業集團金網絡(北京)電子商務有限公司副總經理劉正珩:航空“智”造的供應鏈支撐平臺...

編者按 “十三五”時期是我國貿易發展的重要戰略機遇期&#xff0c;物流產業發展迅速&#xff0c;智慧供應鏈已經成為推動流通大國向流通強國過程中的重要行動。6月2日&#xff0c;由上海市國有資產監督管理委員會、上海市郵政管理局、上海市商務委員會指導&#xff0c;上海市國…

創建、檢查和反編譯世界上(幾乎)最短的 C# 程序

創建、檢查和反編譯世界上&#xff08;幾乎&#xff09;最短的 C# 程序原文來自https://www.stevejgordon.co.uk/creating-inspecting-decompiling-the-worlds-smallest-csharp-program在這篇文章中&#xff0c;我認為創建世界上&#xff08;幾乎&#xff09;最短的 C# 程序然后…

Linux下畫原理圖和PCB

Linux下畫原理圖和PCBWindows下大名鼎鼎的Allegro和經典的Protel 99SE都是不支持Linux操作系統的。做Linux驅動開發免不了要看一下原理圖和PCB。一般的做法有三種&#xff1a; 1.主機使用Windows系統&#xff0c;將Linux裝在VMWARE之類的虛擬機中這樣能夠使用Windows下的軟件看…

配置中心 App Configuration (二):Feature Flag 功能開關特性

寫在前面Web服務開發過程中我們經常有這樣的需求&#xff1a;某些功能我必須我修改了配置才啟用&#xff0c;比如新用戶注冊送券等&#xff1b;某個功能需到特定的時間才啟用&#xff0c;過后就失效&#xff0c;比如春節活動等&#xff1b;某些功能&#xff0c;我想先對10%的用…

oracle臨時表空間

--查看臨時表空間SELECT * FROM v$tablespace;SELECT * FROM dba_tablespaces;--查看所有臨時表空間文件SELECT * FROM dba_data_files;--查看臨時臨時表空間文件SELECT * FROM dba_temp_files;--查看臨時表空間組SELECT * FROM dba_tablespace_groups; --查找默認臨時表空間SE…

ES 2022 正式發布!有哪些新特性?

2022 年 6 月 22 日&#xff0c;第 123 屆 Ecma 大會批準了 ECMAScript 2022 語言規范[1]&#xff0c;這意味著它現在正式成為標準。 1 ECMAScript 2022編輯 本次發布的編輯有&#xff1a; Shu-yu Guo[2] Michael Ficarra[3] Kevin Gibbons[4] 2 ECMAScript 2022有什么新內…

聯想(Lenovo)小新310經典版進bios方法

1&#xff0c;找到novo按鈕。 2&#xff0c;在關機的狀態下桶一下小孔&#xff0c;不用任何操作&#xff0c;電腦進入bios選擇界面。轉載于:https://www.cnblogs.com/senior-engineer/p/6761457.html

C#中的匿名類型

這節來講一下C#中的匿名類型。匿名類在C#中&#xff0c;我們可以不去顯示的聲明一個類&#xff0c;而是通過匿名類去臨時聲明一個類結構去幫助我們去完成一些功能。聲明一個匿名類&#xff0c;我們可以像下面這樣做&#xff1a;var Anonymousnew {name"charles",year…

MySQL之MHA高可用集群

目錄 一、MHA概述 1.1.MHA 是什么 1.2.MHA 的組成 1.3.MHA 的特點 二、MHA搭建準備 2.1.實驗思路 三、MHA搭建 3.1配置主從復制 3.2.安裝 MHA 軟件 3.3.故障模擬 3.4.故障修復 四、總結 一、MHA概述 1.1.MHA 是什么 1.MHA&#xff08;MasterHigh Availability&…

Tensorflow之安裝

1.fellow the instruction of https://www.tensorflow.org/install/install_linux#installing_with_anaconda 2.anaconda安裝&#xff0c;修改~/.bash_profile為 export PATH~/anaconda2/bin:/usr/local/cuda/bin:$PATHexport LD_LIBRARY_PATH/usr/local/cuda/lib64:$LD_LIBRAR…

2、Saltstack的數據系統

一、Grainsgrains是salt用來收集minion端底層系統信息的接口。比如&#xff0c;操作系統type、域名 、IP地址、內存及其他相關系統屬性信息等。存儲在minion端&#xff0c;用于保存minion端數據信息。minion啟動時才加載grains信息&#xff0c;所以他時靜態的&#xff0c;Grain…

配置中心 App Configuration (一):輕松集成到Asp.Net Core

寫在前面在日常開發中&#xff0c;我這邊比較熟悉的配置中心有&#xff0c;攜程Apollo&#xff0c;阿里Nacos(配置中心&#xff0c;服務治理一體)之前文章&#xff1a;Asp.Net Core與攜程阿波羅(Apollo)的第一次親密接觸總體來說&#xff0c;Apollo和Nacos社區都比較活躍&#…

stop-hbase.sh一直處于等待狀態

今天關閉HBase時&#xff0c;輸入stop-hbase.sh一直處于等待狀態 解決方法&#xff1a; 先輸入&#xff1a;hbase-daemon.sh stop master 再輸入&#xff1a;stop-hbase.sh就可以關閉HBase集群了。 轉載于:https://www.cnblogs.com/lijinze-tsinghua/p/8667761.html

shell編程100例

1、編寫hello world腳本 #!/bin/bash# 編寫hello world腳本echo "Hello World!"2、通過位置變量創建 Linux 系統賬戶及密碼 #!/bin/bash# 通過位置變量創建 Linux 系統賬戶及密碼#$1 是執行腳本的第一個參數,$2 是執行腳本的第二個參數 useradd "$1" …

sqlserver 分頁

select top 10 numComImg.* from( select row_number() over(order by id asc) as rownumber,* from (select * FROM [TCCLine].[dbo].[CLine_CommonImage]) as comImg)as numComImg where rownumber>40select top 10 * --10 為頁大小from [TCCLine].[dbo].[CLine_CommonIma…