自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java高并發(fā)編程基礎三大利器之CountDownLatch

開發(fā) 后端
CountDownLatch是通過一個計數(shù)器來實現(xiàn)的,計數(shù)器的初始值是線程的數(shù)量。每當一個線程執(zhí)行完畢后,計數(shù)器的值就減1,當計數(shù)器的值為0時,表示所有線程都執(zhí)行完畢,然后在閉鎖上(調(diào)用await方法的線程)等待的線程就可以恢復工作了。

[[386772]]

 什么是CountDownLatch

CountDownLatch是通過一個計數(shù)器來實現(xiàn)的,計數(shù)器的初始值是線程的數(shù)量。每當一個線程執(zhí)行完畢后,計數(shù)器的值就減1,當計數(shù)器的值為0時,表示所有線程都執(zhí)行完畢,然后在閉鎖上(調(diào)用await方法的線程)等待的線程就可以恢復工作了。

應用場景

CountDownLatch可以用來干什么呢?有什么應用場景?實際項目中有應用的場景嗎?這應該才是大家比較關心的。我們先來看看官網(wǎng)提供的例子是如何進行應用的https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html 官方提供了兩個demo我直接把它轉成了圖片順帶推薦下這個代碼轉圖片的網(wǎng)址https://www.dute.org/code-snapshot 還挺好用的。

官網(wǎng)demo1

★The first is a start signal that prevents any worker from proceeding until the driver is ready for them to proceed; The second is a completion signal that allows the driver to wait until all workers have completed.”

  • 第一個開始信號(startSignal)會阻止任何工人(worker )開始工作,在司機到來之前。說白了就是司機沒來工人就不能干活。
  • 第二個是完成信號 (doneSignal),允許司機 Driver 等待,直到所有的工人完成.說白了就是司機要等到所有工人完工為止。

官網(wǎng)demo2

★Another typical usage would be to divide a problem into N parts, describe each part with a Runnable that executes that portion and counts down on the latch, and queue all the Runnables to an Executor. When all sub-parts are complete, the coordinating thread will be able to pass through await.”

另一種典型的用法就是把一個大任務拆分N個部分,讓多個線程(Worker)執(zhí)行,每個線程(Worker)執(zhí)行完自己的部分計數(shù)器就減1,當所有子部分都完成后,Driver 才繼續(xù)向下執(zhí)行才繼續(xù)執(zhí)行。就好比富士康手機加工的流水線一樣,組裝一步手機需要一條條的流水線來相互配合完成。一條條流水線(Worker),每條線都干自己的活。有的流水線是貼膜的,有的流水線是打螺絲的,有的流水線是質檢的、有的流水線充電的、有的流水線貼膜的。等這些流水線都干完了就把一部手機組裝完成了。

上面兩個就是官方提供的demo,下面我再來兩個我們平時開發(fā)中可以用到的栗子:

多個線程等待:模擬并發(fā),讓并發(fā)線程一起執(zhí)行。

有時候我們寫了接口想去壓測下它,看看它的最大并發(fā)數(shù)大概是多少。當然我們可以使用Jmeter來進行壓測,但是有時候我們不想去下載工具,其實就可以借助CountDownLatch來實現(xiàn)。

  1. /** 
  2.  * @author: 公眾號:java金融 
  3.  */ 
  4. public class TestCountDownLatch1 { 
  5.      public static void main(String[] args) throws InterruptedException { 
  6.           CountDownLatch countDownLatch = new CountDownLatch(1); 
  7.           for (int i = 0; i < 5; i++) { 
  8.                new Thread(() -> { 
  9.                     try { 
  10.                          //所有請求都阻塞在這,等待 
  11.                          countDownLatch.await(); 
  12.                          // 調(diào)用測試接口 
  13.                          System.out.println(Thread.currentThread().getName() + "開始執(zhí)行……"); 
  14.                     } catch (InterruptedException e) { 
  15.                          e.printStackTrace(); 
  16.                     } 
  17.                }).start(); 
  18.           } 
  19.           // 讓請求都準備好 
  20.           Thread.sleep(2000); 
  21.           // 讓所有請求統(tǒng)一請求 
  22.           countDownLatch.countDown(); 
  23.      } 

我們通過CountDownLatch.await(),讓多個參與者線程啟動后阻塞等待,然后在主線程 調(diào)用CountDownLatch.countdown() 將計數(shù)減為0,讓所有線程一起往下執(zhí)行;以此實現(xiàn)了多個線程在同一時刻并發(fā)執(zhí)行,來模擬并發(fā)請求的目的。

單個線程等待:多個線程(任務)完成后,進行匯總合并

  1. /** 
  2.  * @author: 公眾號:java金融 
  3.  */ 
  4. public class TestCountDownLatch1 { 
  5.      public static void main(String[] args) throws InterruptedException { 
  6.           int count = 3; 
  7.           CountDownLatch countDownLatch = new CountDownLatch(count); 
  8.           for (int i = 0; i < count; i++) { 
  9.                final int index = i; 
  10.                new Thread(() -> { 
  11.                     try { 
  12.                          Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(1000)); 
  13.                          System.out.println("finish" + index + Thread.currentThread().getName()); 
  14.                     } catch (InterruptedException e) { 
  15.                          e.printStackTrace(); 
  16.                     }finally{ 
  17.                         countDownLatch.countDown(); 
  18.                     } 
  19.                }).start(); 
  20.           } 
  21.           countDownLatch.await();// 主線程在阻塞,當計數(shù)器==0,就喚醒主線程往下執(zhí)行。 
  22.           System.out.println("主線程:在所有任務運行完成后,進行結果匯總"); 
  23.      } 

這種場景應該是用的最多了,比如我們打開一個電商的個人中心頁面,我們需要調(diào)用,用戶信息接口、用戶訂單接口、用戶會員信息等接口,然后合并后一起給到前端,假設每個接口最長耗時為1s,如果我們同步調(diào)用的話最大耗時時間是3s,如果我們采用異步調(diào)用然后合并結果,所以最大的耗時時間是3s。每個接口調(diào)用返回數(shù)據(jù)后調(diào)用countDown方法,讓計數(shù)器進行減1,當把計數(shù)器減為0時的這個線程會去喚醒主線程,讓它繼續(xù)往下走。

CountDownLatch 實現(xiàn)原理

CountDownLatch是通過AQS的state字段來實現(xiàn)的一個計數(shù)器,計數(shù)器的初始值(state的值)為new CountDownLatch設置的數(shù)量,每次調(diào)用countDown的時候,state的值會進行減1,最后某個線程將state值減為0時,會把調(diào)用了await()進行阻塞等待的線程進行喚醒。CountDownLatch重寫了tryReleaseShared這個方法,只有當state這個字段被設置為0時,也就是tryReleaseShared返回true的情況就會執(zhí)行doReleaseShared方法,把調(diào)用了await的線程進行喚醒。

  1. public final boolean releaseShared(int arg) { 
  2.       if (tryReleaseShared(arg)) { 
  3.           doReleaseShared(); 
  4.           return true
  5.       } 
  6.       return false
  7.   } 
  8. rotected boolean tryReleaseShared(int releases) { 
  9.           // Decrement count; signal when transition to zero 
  10.           for (;;) { 
  11.               int c = getState(); 
  12.               if (c == 0) 
  13.                   return false
  14.               int nextc = c-1; 
  15.               if (compareAndSetState(c, nextc)) 
  16.                   return nextc == 0; 
  17.           } 
  18.       } 

CountDownLatch的其他源碼就不進行分析了, 相信看了這兩篇文章《Java高并發(fā)編程基礎之AQS》、《Java高并發(fā)編程基礎三大利器之Semaphore》再來看這個還是比較輕松的。

總結

  • CountDownLatch不能重新初始化或者修改CountDownLatch內(nèi)部計數(shù)器的值。
  • CountDownLatch和Semaphore在使用AQS的方式上很相似,在同步狀態(tài)中都是保存的是當前的計數(shù)值。
  • CountDownLatch的作用就是允許一個或多個線程等待其他線程完成操作,看起來有點類似join() 方法,但其提供了比 join() 更加靈活的API。
  • CountDownLatch可以手動控制在n個線程里調(diào)用n次countDown()方法使計數(shù)器進行減一操作,也可以在一個線程里調(diào)用n次執(zhí)行減一操作。
  • join() 的實現(xiàn)原理是不停檢查join線程是否存活,如果 join 線程存活則讓當前線程永遠等待。所以兩者之間相對來說還是CountDownLatch使用起來較為靈活。

本文轉載自微信公眾號「java金融」,可以通過以下二維碼關注。轉載本文請聯(lián)系java金融公眾號。

 

 

責任編輯:武曉燕 來源: java金融
相關推薦

2021-03-18 00:14:29

JavaCyclicBarri高并發(fā)

2021-03-04 07:24:24

JavaSemaphore高并發(fā)

2020-08-27 08:17:05

緩存高并發(fā)系統(tǒng)

2021-02-26 13:08:27

Java高并發(fā)AQS

2024-11-13 15:09:57

Java線程開發(fā)

2014-03-14 10:34:28

JavaJava并發(fā)

2019-09-16 09:23:34

高并發(fā)編程CountDownLaCyclicBarri

2024-11-21 14:55:37

2022-07-02 08:40:00

并發(fā)編程

2020-09-21 06:53:41

NoSQL高并發(fā)面試

2022-11-27 08:12:11

RocketMQ源碼工具類

2011-07-05 14:42:46

java

2024-12-27 09:08:25

2019-11-07 09:20:29

Java線程操作系統(tǒng)

2021-08-05 07:58:22

并發(fā)編程包Task

2024-04-02 09:40:39

多線程Java原子性

2024-09-02 22:49:33

2016-11-28 09:08:43

java系統(tǒng)異步非阻塞

2021-02-14 18:26:25

高并發(fā)大對象代碼

2011-06-13 10:41:17

JAVA
點贊
收藏

51CTO技術棧公眾號