簡(jiǎn)單地理解區(qū)分CountDownLatch與CyclicBarrier--高并發(fā)編程
本文主要討論在高并發(fā)編程中兩非常實(shí)用工具CyclicBarrier(同步屏障)和CountDownLatch(倒計(jì)時(shí)鎖),兩者都是java.util.concurrent并發(fā)包內(nèi)非常有用的并發(fā)工具類,為了幫助理解會(huì)結(jié)合一些有趣的比喻,下面將對(duì)兩者進(jìn)行討論。
一、CountDownLatch倒計(jì)時(shí)鎖(一個(gè)線程等待另外N個(gè)線程完成某個(gè)事情之后才能執(zhí)行)
- //創(chuàng)建一個(gè)倒計(jì)時(shí)鎖,設(shè)置值為5
- final CountDownLatch latch = new CountDownLatch(5);
- try {
- //啟用5個(gè)線程
- 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("捕獲異常");
- }
- }
運(yùn)行結(jié)果:
解析:倒計(jì)時(shí)鎖理解起來比較容易,這里通過結(jié)合實(shí)際場(chǎng)景幫助理解。場(chǎng)景:一張數(shù)據(jù)表中存放大量的數(shù)據(jù),現(xiàn)要讀取表里的所有信息。為了提高讀取效率便通過在主線程中開啟多個(gè)子線程分工合作對(duì)數(shù)據(jù)表進(jìn)行讀取。接下來要等待全部子線程讀取完畢之后,將讀取到的內(nèi)容進(jìn)行匯總并在主線程中進(jìn)行處理。
- 首先先設(shè)置一個(gè)CountDownLatch倒計(jì)時(shí)鎖 ,并設(shè)置倒計(jì)時(shí)值為5
- 每一個(gè)子線程進(jìn)行自己的工作,當(dāng)工作執(zhí)行完畢完畢后通過執(zhí)行l(wèi)atch.countDown()對(duì)倒計(jì)時(shí)鎖的值進(jìn)行減1操作,表示自己工作完成。
- 主線程latch.await() 后的代碼段一直屬于等待狀態(tài),直到CountDownLatch的值為0時(shí)才繼續(xù)執(zhí)行。
二、可循環(huán)使用的屏障CyclicBarrier(N個(gè)線程相互等待,任何一個(gè)線程完成之前,所有的線程都必須等待)
- //建立一個(gè)屏障并設(shè)定一個(gè)值,當(dāng)有足夠的線程達(dá)到屏障時(shí)再一起釋放
- 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 + "號(hào)玩家,已準(zhǔn)備好,等待進(jìn)入游戲");
- barrier.await();
- System.out.println(num + "號(hào)玩家,已經(jīng)進(jìn)入游戲");
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (BrokenBarrierException e) {
- e.printStackTrace();
- }
- });
- }
- executorPool.shutdown();
運(yùn)行結(jié)果:
解析:這里通過一個(gè)形象的例子來幫助理解CyclicBarrier。
- 一開始建立一個(gè)CyclicBarrier對(duì)象并設(shè)置parties的值為5(理解為開啟一個(gè)游戲房間,且需要5個(gè)玩家都準(zhǔn)備好的條件之后才能開啟游戲,各個(gè)玩家才能進(jìn)行游戲游玩)。
- 循環(huán)開啟多個(gè)線程并各自調(diào)用barrier.await(),理解為玩家分別都進(jìn)入房間并做好了準(zhǔn)備,線程當(dāng)調(diào)用barrier.await()方法計(jì)數(shù)會(huì)加1,如果計(jì)數(shù)還達(dá)不到CyclicBarrier預(yù)先設(shè)置的parties值時(shí)則該線程會(huì)進(jìn)入等待狀態(tài)。
- 當(dāng)線程barrier.await()方法計(jì)數(shù)達(dá)到CyclicBarrier預(yù)先設(shè)置的parties值時(shí),便開始游戲。這個(gè)時(shí)候所有的線程(玩家)便同時(shí)進(jìn)入到了游戲中。
三、兩者對(duì)比
最后
CyclicBarrier(同步屏障)和CountDownLatch(倒計(jì)時(shí)鎖)都是不錯(cuò)的高并發(fā)編程工具類,兩者很相似容易造成混淆,通過理解兩者各自工作方式和特點(diǎn)并結(jié)合業(yè)務(wù)需求合理地應(yīng)用他們會(huì)有不錯(cuò)的效益。