網(wǎng)站首頁 編程語言 正文
Semaphore,CountdownLatch,CyclicBarrier都是java提供的同步輔助類。
上一篇對Semaphore有了一定的了解,本篇則針對CountdownLatch以及CyclicBarrier進行一定的總結(jié)。
一、CountdownLatch
1)CountdownLatch是什么?
CyclicBarrier的字面意思是可循環(huán)使用(Cyclic)的屏障(Barrier)
能夠使一個線程等待其他線程完成各自的工作之后再執(zhí)行。例如zookeeper分布式鎖的實現(xiàn)。而Semaphore則主要強調(diào)的是資源有限。
2)CountdownLatch使用場景
比如老公陪同媳婦去醫(yī)院,媳婦等候醫(yī)生看病,老公則針對單子去拿藥,兩者都完工,則一起回家。再比如老板等10個員工開會,只有10個員工都到齊了,會議才能開始等等場景。
3)應用demo
舉例說明老板等待員工開會的場景:
public static void main(String[] args) {
//老板需要等待15個員工會議室開會
final CountDownLatch latch = new CountDownLatch(15);
for (int i = 0; i < 15; i++) {
Random random = new Random();
final int timer = random.nextInt(1000);
new Thread(() -> {
try {
System.out.println("子線程" + Thread.currentThread().getName() + "正在趕路");
//模仿每個員工走自己線程需要的時間
Thread.sleep(1000 + timer);
//調(diào)用latch的countDown方法使計數(shù)器-1;一共15個
latch.countDown();
System.out.println("子線程" + Thread.currentThread().getName() + "到會議室了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
try {
System.out.println("領(lǐng)導等待員工會議室開會...");
//主線程阻塞等待計數(shù)器歸零
latch.await();
System.out.println("員工都來了,會議開始");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
執(zhí)行結(jié)果:
子線程Thread-1正在趕路
子線程Thread-3正在趕路
子線程Thread-0正在趕路
子線程Thread-2正在趕路
子線程Thread-4正在趕路
子線程Thread-5正在趕路
子線程Thread-6正在趕路
子線程Thread-7正在趕路
子線程Thread-8正在趕路
子線程Thread-9正在趕路
子線程Thread-10正在趕路
子線程Thread-11正在趕路
子線程Thread-12正在趕路
子線程Thread-13正在趕路
領(lǐng)導等待員工會議室開會…
子線程Thread-14正在趕路
子線程Thread-5到會議室了
子線程Thread-1到會議室了
子線程Thread-12到會議室了
子線程Thread-13到會議室了
子線程Thread-4到會議室了
子線程Thread-6到會議室了
子線程Thread-2到會議室了
子線程Thread-0到會議室了
子線程Thread-3到會議室了
子線程Thread-10到會議室了
子線程Thread-14到會議室了
子線程Thread-8到會議室了
子線程Thread-9到會議室了
子線程Thread-7到會議室了
子線程Thread-11到會議室了
員工都來了,會議開始
4)源碼分析
核心關(guān)注方法只有兩個,latch.countDown();和latch.await();
countDown() 方法每次調(diào)用都會將 state 減 1,直到state 的值為 0;而 await 是一個阻塞方法,當 state 減 為 0 的時候,await 方法才會返回。await 可以被多個線程調(diào)用,大家在這個時候腦子里要有個圖:所有調(diào)用了await 方法的線程阻塞在 AQS 的阻塞隊列中,等待條件滿(state == 0),將線程從隊列中一個個喚醒過來。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
在 CountDownLatch 內(nèi)部寫了一個 Sync 并且繼承了 AQS 這個抽象類重寫了 AQS中的共享鎖方法。這段代碼主要是判定當前線程是否獲取到了共享鎖
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//state 如果不等于 0,說明當前線程需要加入到共享鎖隊列中
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
//在共享可中斷模式下獲取。
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
//創(chuàng)建一個共享模式的節(jié)點添加到隊列中
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
//嘗試獲取鎖
int r = tryAcquireShared(arg);
//r>=0 表示獲取到了執(zhí)行權(quán)限,這個時候因為 state!=0,所以不會執(zhí)行這段代碼
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
//阻塞線程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
二、CyclicBarrier
1)CyclicBarrier是什么?
柵欄屏障,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續(xù)運行。
簡單理解就是:多個線程之間互相等待,滿足條件在同一時間進行。
2)CyclicBarrier使用場景
可以用于多線程計算數(shù)據(jù),最后合并計算結(jié)果的場景。
又比如旅行團旅行,需要大家都到齊,證件都辦理好,才能出發(fā)。
3)應用demo
旅行團旅行,需要大家都到齊,證件都辦理好,上旅行車才能出發(fā)。
public class CyclicBarrierTest1 extends Thread{
private final CyclicBarrier barrier;
//隨機值處理
private final Random random = new Random();
public CyclicBarrierTest1(String name,CyclicBarrier barrier) {
super(name);
this.barrier = barrier;
}
/**
* 重寫run方法
*/
@Override
public void run() {
try {
Thread.sleep(random.nextInt(2000));
System.out.println(Thread.currentThread().getName() + " - 已經(jīng)到達旅行團");
barrier.await();
Thread.sleep(random.nextInt(2000));
System.out.println(Thread.currentThread().getName() + " - 證件已經(jīng)辦理好");
barrier.await();
Thread.sleep(random.nextInt(2000));
System.out.println(Thread.currentThread().getName() + " - 已經(jīng)上旅行車");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
super.run();
}
public static void main(String[] args) {
//旅行團5個游客
CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
for (int i=0;i<5;i++){
new CyclicBarrierTest1("游客-" + (i + 1), cyclicBarrier).start();
}
}
}
游客-5 - 已經(jīng)到達旅行團
游客-3 - 已經(jīng)到達旅行團
游客-2 - 已經(jīng)到達旅行團
游客-1 - 已經(jīng)到達旅行團
游客-4 - 已經(jīng)到達旅行團
游客-2 - 證件已經(jīng)辦理好
游客-4 - 證件已經(jīng)辦理好
游客-1 - 證件已經(jīng)辦理好
游客-3 - 證件已經(jīng)辦理好
游客-5 - 證件已經(jīng)辦理好
游客-1 - 已經(jīng)上旅行車
游客-2 - 已經(jīng)上旅行車
游客-3 - 已經(jīng)上旅行車
游客-5 - 已經(jīng)上旅行車
游客-4 - 已經(jīng)上旅行車
原文鏈接:https://blog.csdn.net/huo065000/article/details/120649318
相關(guān)推薦
- 2022-10-23 Go?數(shù)據(jù)結(jié)構(gòu)之堆排序示例詳解_Golang
- 2022-12-04 Python?棧實現(xiàn)的幾種方式及優(yōu)劣詳解_python
- 2023-10-10 uniapp省市區(qū)選擇 支持微信小程序 支持回顯 支持一列兩列三列
- 2022-01-27 worker process terminated 進程退出
- 2022-11-12 C語言內(nèi)存操作函數(shù)使用示例梳理講解_C 語言
- 2022-07-15 Sql?Server存儲過程詳解_MsSql
- 2022-06-12 淺談Android?Dialog窗口機制_Android
- 2022-11-17 淺析golang的依賴注入_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支