《死磕 Java 并發編程》系列連載中,大家可以關注一波:
👍🏻『死磕Java并發編程系列』 01 十張圖告訴你多執行緒那些破事
『死磕Java并發編程系列』 02 面試官:說說什么是Java記憶體模型?
『死磕Java并發編程系列』 03 面試必問的CAS原理你會了嗎?
『死磕Java并發編程系列』 04 面試官:說說Atomic原子類的實作原理?
👍🏻『死磕Java并發編程系列』 05 圖解Java中那18 把鎖
在日常編碼中,Java 并發編程可是少不了,試試下面這些并發編程工具類,
今天先帶領大家一起重溫學習 CountDownLatch 這個牛叉的工具類,
認識 CountDownLatch
CountDownLatch是一個同步工具類,用來協調多個執行緒之間的同步,或者說起到執行緒之間通信的作用(非互斥),
CountDownLatch 能夠使一個執行緒在等待另外一些執行緒完成各自作業之后,再繼續執行,使用一個計數器進行實作,計數器初始值為執行緒的數量,當每一個執行緒完成自己任務后,計數器的值就會減一,當計數器的值為0時,表示所有的執行緒都已經完成一些任務,然后在CountDownLatch上等待的執行緒就可以恢復執行接下來的任務,

CountDownLatch 的使用
CountDownLatch類使用起來非常簡單,
Class 位于:java.util.concurrent.CountDownLatch
下面簡單介紹它的構造方法和常用方法,
構造方法
CountDownLatch只提供了一個構造方法:
// count 為初始計數值
public CountDownLatch(int count) {
// ……
}
常用方法
//常用方法1:呼叫await()方法的執行緒會被掛起,它會等待直到count值為0才繼續執行
public void await() throws InterruptedException {
// ……
}
// 常用方法2:和await()類似,只不過等待超時后count值還沒變為0的話就會繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
// ……
}
// 常用方法3:將count值減1
public void countDown() {
// ……
}
CountDownLatch 的應用場景
我們考慮一個場景:用戶購買一個商品下單成功后,我們會給用戶發送各種訊息提示用戶『購買成功』,比如發送郵件、微信訊息、短信等,所有的訊息都發送成功后,我們在后臺記錄一條訊息表示成功,
當然我們可以使用單執行緒去完成,逐個完成每個操作,如下圖所示:

但是這樣效率就會非常低,如何解決單執行緒效率低的問題?當然是通過多執行緒啦,
使用多執行緒也會遇到一個問題,子執行緒訊息還沒發送完,主執行緒可能就已經打出『所有的訊息都已經發送完畢啦』,這在邏輯上肯定是不對的,我們期望所有子執行緒發完訊息主執行緒才會列印訊息,怎么實作呢?CountDownLatch就可以解決這一類問題,

我們使用代碼實作上面的需求,
import java.util.concurrent.*;
public class OrderServiceDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("main thread: Success to place an order");
int count = 3;
CountDownLatch countDownLatch = new CountDownLatch(count);
Executor executor = Executors.newFixedThreadPool(count);
executor.execute(new MessageTask("email", countDownLatch));
executor.execute(new MessageTask("wechat", countDownLatch));
executor.execute(new MessageTask("sms", countDownLatch));
// 主執行緒阻塞,等待所有子執行緒發完訊息
countDownLatch.await();
// 所有子執行緒已經發完訊息,計數器為0,主執行緒恢復
System.out.println("main thread: all message has been sent");
}
static class MessageTask implements Runnable {
private String messageName;
private CountDownLatch countDownLatch;
public MessageTask(String messageName, CountDownLatch countDownLatch) {
this.messageName = messageName;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
// 執行緒發送訊息
System.out.println("Send " + messageName);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
// 發完訊息計數器減 1
countDownLatch.countDown();
}
}
}
}
程式運行結果:
main thread: Success to place an order
Send email
Send wechat
Send sms
main thread: all message has been sent
從運行結果可以看到主執行緒是在所有的子執行緒發送完訊息后才列印,這符合我們的預期,
CountDownLatch 的限制
CountDownLatch是一次性的,計算器的值只能在構造方法中初始化一次,之后沒有任何機制再次對其設定值,當CountDownLatch使用完畢后,它不能再次被使用,
大家學會了么?后面會接著講剩余的幾種并發工具類,拭目以待吧~

我是雷小帥,愛了~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/300461.html
標籤:java
下一篇:??高級JAVA開發必備技能??java8 JSR-310判斷是否閏年實作,發現原作者的代碼可能有問題(JAVA 小虛竹,建議收藏)
