当前位置:网站首页>4年工作經驗,多線程間的5種通信方式都說不出來,你敢信?
4年工作經驗,多線程間的5種通信方式都說不出來,你敢信?
2022-06-25 01:07:00 【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<>();
//線程A
Thread 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;
}
});
//線程B
Thread threadB = new Thread(() -> {
while (true) {
if (notice) {
System.out.println("線程B收到通知,開始執行自己的業務...");
break;
}
}
});
//需要先啟動線程B
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再啟動線程A
threadA.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<>();
// 線程A
Thread 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線程
}
}
});
//線程B
Thread threadB = new Thread(() -> {
while (true) {
synchronized (lock) {
if (list.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("線程B收到通知,開始執行自己的業務...");
}
}
});
//需要先啟動線程B
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//再啟動線程A
threadA.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<>();
//線程A
Thread 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();
}
});
//線程B
Thread threadB = new Thread(() -> {
while (true) {
if (list.size() != 5) {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("線程B收到通知,開始執行自己的業務...");
break;
}
});
//需要先啟動線程B
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//再啟動線程A
threadA.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<>();
//線程A
Thread 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();
});
//線程B
Thread 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<>();
//線程B
final Thread threadB = new Thread(() -> {
if (list.size() != 5) {
LockSupport.park();
}
System.out.println("線程B收到通知,開始執行自己的業務...");
});
//線程A
Thread 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();
}
}來源:blog.csdn.net/ChineseSoftware/article/
details/118390388
推薦

PS:因為公眾號平臺更改了推送規則,如果不想錯過內容,記得讀完點一下“在看”,加個“星標”,這樣每次新文章推送才會第一時間出現在你的訂閱列錶裏。點“在看”支持我們吧!
边栏推荐
- ImageView展示网络图片
- Custom control - round dot progress bar (imitating one key acceleration in security guard)
- Mysql database Chapter 1 Summary
- Text editor for QT project practice - Episode 12
- 丹麦技术大学首创将量子计算应用于能源系统潮流建模
- Practical operation notes - notebook plus memory and ash cleaning
- Scala object blending trait
- Network request -volley
- The problem of multiple callback of video ads stimulated by applets (offcolse problem)
- Several ways for wechat applet to jump to the page are worth collecting
猜你喜欢

百公里加速仅5.92秒,威兰达高性能版以高能产品实力领跑

图书馆管理系统代码源码(php+css+js+mysql) 完整的代码源码

Infotnews | is the development of domestic NFT limited to digital collections?

Activity startup process

JS Chapter 1 Summary

Single blind box removal, social blind box and friend blind box program source code

使用 Loki 微服务模式部署生产集群

Xcode preview displays a bug in the content of the list view and its solution

Add information on the left and add parts on the right of the status bar

【微服务|Sentinel】簇点链路|微服务集群环境搭建
随机推荐
JSON file of China's provincial boundaries
2022 melting welding and thermal cutting recurrent training question bank simulated examination platform operation
QT (36) -rapidjson parsing nested JSON
大厂高频软件测试面试题和答案都帮你准备好啦,备战金九银十
丹麥技術大學首創將量子計算應用於能源系統潮流建模
Zuckerberg demonstrated four VR head display prototypes, and meta revealed the "family" of metauniverse
2022r1 quick opening pressure vessel operation test questions and answers
Première application de l'informatique quantique à la modélisation des flux de puissance dans les systèmes énergétiques à l'Université technique danoise
Scala classes inherit multiple attributes
VB 学习笔记
Working principle analysis of kubernetes architecture core components
LLVM TargetPassConfig
Text editor for QT project practice - Episode 12
2021-02-15
Text editor for QT project practice -- Episode 9
Leetcode 1248. 统计「优美子数组」(害,突然发现只会暴力枚举了)
百公里加速仅5.92秒,威兰达高性能版以高能产品实力领跑
Scala template method pattern
扎克伯格上手演示四款VR头显原型机,Meta透露元宇宙「家底」
Scala sample class case calculate