簡單地理解區(qū)分CountDownLatch與CyclicBarrier--高并發(fā)編程
本文主要討論在高并發(fā)編程中兩非常實用工具CyclicBarrier(同步屏障)和CountDownLatch(倒計時鎖),兩者都是java.util.concurrent并發(fā)包內(nèi)非常有用的并發(fā)工具類,為了幫助理解會結(jié)合一些有趣的比喻,下面將對兩者進(jìn)行討論。
一、CountDownLatch倒計時鎖(一個線程等待另外N個線程完成某個事情之后才能執(zhí)行)
- //創(chuàng)建一個倒計時鎖,設(shè)置值為5
 - final CountDownLatch latch = new CountDownLatch(5);
 - try {
 - //啟用5個線程
 - for (int i = 1; i <= 5; i++) {
 - new Thread(new Runnable() {
 - @Override
 - public void run() {
 - try {
 - Thread.sleep(1000);
 - } catch (Exception e) {
 - e.printStackTrace();
 - }
 - System.out.println("子線程執(zhí)行!");
 - //讓latch鎖中的數(shù)值減1
 - latch.countDown();
 - }
 - }).start();
 - }
 - //處于阻塞狀態(tài)直到latch中數(shù)值為零才執(zhí)行后續(xù)操作
 - latch.await();
 - System.out.println("主線程執(zhí)行");
 - } catch (Exception e) {
 - System.out.println("捕獲異常");
 - }
 - }
 
運行結(jié)果:

解析:倒計時鎖理解起來比較容易,這里通過結(jié)合實際場景幫助理解。場景:一張數(shù)據(jù)表中存放大量的數(shù)據(jù),現(xiàn)要讀取表里的所有信息。為了提高讀取效率便通過在主線程中開啟多個子線程分工合作對數(shù)據(jù)表進(jìn)行讀取。接下來要等待全部子線程讀取完畢之后,將讀取到的內(nèi)容進(jìn)行匯總并在主線程中進(jìn)行處理。
- 首先先設(shè)置一個CountDownLatch倒計時鎖 ,并設(shè)置倒計時值為5
 - 每一個子線程進(jìn)行自己的工作,當(dāng)工作執(zhí)行完畢完畢后通過執(zhí)行l(wèi)atch.countDown()對倒計時鎖的值進(jìn)行減1操作,表示自己工作完成。
 - 主線程latch.await() 后的代碼段一直屬于等待狀態(tài),直到CountDownLatch的值為0時才繼續(xù)執(zhí)行。
 
二、可循環(huán)使用的屏障CyclicBarrier(N個線程相互等待,任何一個線程完成之前,所有的線程都必須等待)
- //建立一個屏障并設(shè)定一個值,當(dāng)有足夠的線程達(dá)到屏障時再一起釋放
 - CyclicBarrier barrier = new CyclicBarrier(5, () -> {
 - System.out.println("開始游戲");
 - });
 - ExecutorService executorPool = Executors.newCachedThreadPool();
 - for (int i = 1; i <= 5; i++) {
 - int num = i;
 - Thread.sleep(1000);
 - executorPool.execute(() -> {
 - try {
 - System.out.println(num + "號玩家,已準(zhǔn)備好,等待進(jìn)入游戲");
 - barrier.await();
 - System.out.println(num + "號玩家,已經(jīng)進(jìn)入游戲");
 - } catch (InterruptedException e) {
 - e.printStackTrace();
 - } catch (BrokenBarrierException e) {
 - e.printStackTrace();
 - }
 - });
 - }
 - executorPool.shutdown();
 
運行結(jié)果:

解析:這里通過一個形象的例子來幫助理解CyclicBarrier。
- 一開始建立一個CyclicBarrier對象并設(shè)置parties的值為5(理解為開啟一個游戲房間,且需要5個玩家都準(zhǔn)備好的條件之后才能開啟游戲,各個玩家才能進(jìn)行游戲游玩)。
 - 循環(huán)開啟多個線程并各自調(diào)用barrier.await(),理解為玩家分別都進(jìn)入房間并做好了準(zhǔn)備,線程當(dāng)調(diào)用barrier.await()方法計數(shù)會加1,如果計數(shù)還達(dá)不到CyclicBarrier預(yù)先設(shè)置的parties值時則該線程會進(jìn)入等待狀態(tài)。
 - 當(dāng)線程barrier.await()方法計數(shù)達(dá)到CyclicBarrier預(yù)先設(shè)置的parties值時,便開始游戲。這個時候所有的線程(玩家)便同時進(jìn)入到了游戲中。
 

三、兩者對比

最后
CyclicBarrier(同步屏障)和CountDownLatch(倒計時鎖)都是不錯的高并發(fā)編程工具類,兩者很相似容易造成混淆,通過理解兩者各自工作方式和特點并結(jié)合業(yè)務(wù)需求合理地應(yīng)用他們會有不錯的效益。















 
 
 











 
 
 
 