欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java并發(fā)學(xué)習(xí)-CountDownLatch實(shí)現(xiàn)原理全面講解

 更新時(shí)間:2021年02月18日 10:36:13   作者:康斌825  
這篇文章主要介紹了java并發(fā)學(xué)習(xí)-CountDownLatch實(shí)現(xiàn)原理全面講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

CountDownLatch在多線程并發(fā)編程中充當(dāng)一個(gè)計(jì)時(shí)器的功能,并且維護(hù)一個(gè)count的變量,并且其操作都是原子操作。

如下圖,內(nèi)部有下static final的Sync類繼承自AQS.

該類主要通過countDown()和await()兩個(gè)方法實(shí)現(xiàn)功能的,首先通過建立CountDownLatch對(duì)象,并且傳入?yún)?shù)即為count初始值。

如果一個(gè)線程調(diào)用了await()方法,那么這個(gè)線程便進(jìn)入阻塞狀態(tài),并進(jìn)入阻塞隊(duì)列。

如果一個(gè)線程調(diào)用了countDown()方法,則會(huì)使count-1;當(dāng)count的值為0時(shí),這時(shí)候阻塞隊(duì)列中調(diào)用await()方法的線程便會(huì)逐個(gè)被喚醒,從而進(jìn)入后續(xù)的操作。

補(bǔ)充:Java并發(fā)包中CountDownLatch的工作原理、使用示例

1. CountDownLatch的介紹

CountDownLatch是一個(gè)同步工具,它主要用線程執(zhí)行之間的協(xié)作。CountDownLatch 的作用和 Thread.join() 方法類似,讓一些線程阻塞直到另一些線程完成一系列操作后才被喚醒。在直接創(chuàng)建線程的年代(Java 5.0 之前),我們可以使用 Thread.join()。在線程池出現(xiàn)后,因?yàn)榫€程池中的線程不能直接被引用,所以就必須使用 CountDownLatch 了。

CountDownLatch主要有兩個(gè)方法,當(dāng)一個(gè)或多個(gè)線程調(diào)用await方法時(shí),這些線程會(huì)阻塞。其它線程調(diào)用countDown方法會(huì)將計(jì)數(shù)器減1(調(diào)用countDown方法的線程不會(huì)阻塞),當(dāng)計(jì)數(shù)器的值變?yōu)?時(shí),因await方法阻塞的線程會(huì)被喚醒,繼續(xù)執(zhí)行。

實(shí)現(xiàn)原理:計(jì)數(shù)器的值由構(gòu)造函數(shù)傳入,并用它初始化AQS的state值。當(dāng)線程調(diào)用await方法時(shí)會(huì)檢查state的值是否為0,如果是就直接返回(即不會(huì)阻塞);如果不是,將表示該節(jié)點(diǎn)的線程入列,然后將自身阻塞。當(dāng)其它線程調(diào)用countDown方法會(huì)將計(jì)數(shù)器減1,然后判斷計(jì)數(shù)器的值是否為0,當(dāng)它為0時(shí),會(huì)喚醒隊(duì)列中的第一個(gè)節(jié)點(diǎn),由于CountDownLatch使用了AQS的共享模式,所以第一個(gè)節(jié)點(diǎn)被喚醒后又會(huì)喚醒第二個(gè)節(jié)點(diǎn),以此類推,使得所有因await方法阻塞的線程都能被喚醒而繼續(xù)執(zhí)行。

從源代碼和實(shí)現(xiàn)原理中可以看出一個(gè)CountDownLatch對(duì)象,只能使用一次,不能重復(fù)使用。

await方法源碼

public void await() throws InterruptedException {
 sync.acquireSharedInterruptibly(1);
}
 
public final void acquireSharedInterruptibly(int arg)
  throws InterruptedException {
 if (Thread.interrupted())
  throw new InterruptedException();
 if (tryAcquireShared(arg) < 0)
  doAcquireSharedInterruptibly(arg);
}
 
protected int tryAcquireShared(int acquires) {
 return (getState() == 0) ? 1 : -1;
}

doAcquireSharedInterruptibly 主要實(shí)現(xiàn)線程的入列與阻塞。

countDown方法

public void countDown() {
 sync.releaseShared(1);
}
 
public final boolean releaseShared(int arg) {
 if (tryReleaseShared(arg)) {
  doReleaseShared();
  return true;
 }
 return false;
}
 
protected boolean tryReleaseShared(int releases) {
 // Decrement count; signal when transition to zero
 for (;;) {
  int c = getState();
  if (c == 0)
   return false;
  int nextc = c-1;
  if (compareAndSetState(c, nextc))
   return nextc == 0;
 }
}

doReleaseShared主要實(shí)現(xiàn)喚醒第一個(gè)節(jié)點(diǎn),第一個(gè)節(jié)點(diǎn)有會(huì)喚醒第二個(gè)節(jié)點(diǎn),……。

2. 使用示例

package demo; 
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; 
public class CountDownLatchDemo { 
 private CountDownLatch cdl = new CountDownLatch(2); 
 private Random rnd = new Random();
 
 class FirstTask implements Runnable{
 private String id;
 
 public FirstTask(String id){
 this.id = id;
 }
 
 @Override
 public void run(){
 System.out.println("Thread "+ id + " is start");
 try {
 Thread.sleep(rnd.nextInt(1000));
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println("Thread "+ id + " is over");
 cdl.countDown();
 }
 }
 
 class SecondTask implements Runnable{
 private String id;
 
 public SecondTask(String id){
 this.id = id;
 }
 
 @Override
 public void run(){
 try {
 cdl.await();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println("----------Thread "+ id + " is start");
 try {
 Thread.sleep(rnd.nextInt(1000));
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println("----------Thread "+ id + " is over");
 }
 }
 
 public static void main(String[] args){
 ExecutorService es = Executors.newCachedThreadPool();
 CountDownLatchDemo cdld = new CountDownLatchDemo();
 es.submit(cdld.new SecondTask("c"));
 es.submit(cdld.new SecondTask("d"));
 es.submit(cdld.new FirstTask("a"));
 es.submit(cdld.new FirstTask("b"));
 es.shutdown();
 } 
}

在這個(gè)示例中,我們創(chuàng)建了四個(gè)線程a、b、c、d,這四個(gè)線程幾乎同時(shí)提交給了線程池。c線程和d線程會(huì)在a線程和b線程結(jié)束后開始執(zhí)行。

運(yùn)行結(jié)果

Thread a is start
Thread b is start
Thread b is over
Thread a is over
----------Thread c is start
----------Thread d is start
----------Thread d is over
----------Thread c is over

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • Java的Channel通道之FileChannel類詳解

    Java的Channel通道之FileChannel類詳解

    這篇文章主要介紹了Java的Channel通道之FileChannel類詳解,FileChannel類是Java NIO中的一個(gè)重要類,用于在文件中進(jìn)行讀寫操作,它提供了一種高效的方式來處理大文件和隨機(jī)訪問文件的需求,需要的朋友可以參考下
    2023-10-10
  • kafka-console-consumer.sh使用2次grep管道無法提取消息的解決

    kafka-console-consumer.sh使用2次grep管道無法提取消息的解決

    這篇文章主要介紹了kafka-console-consumer.sh使用2次grep管道無法提取消息的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 三行Java代碼實(shí)現(xiàn)計(jì)算多邊形的幾何中心點(diǎn)

    三行Java代碼實(shí)現(xiàn)計(jì)算多邊形的幾何中心點(diǎn)

    因?yàn)楣ぷ餍枰?jì)算采煤機(jī)工作面的中心點(diǎn),如果套用數(shù)學(xué)的計(jì)算公式,用java去實(shí)現(xiàn),太麻煩了。本文將利用java幾何計(jì)算的工具包,幾行代碼就能求出多變形的中心,簡(jiǎn)直yyds!還不快跟隨小編一起學(xué)起來
    2022-10-10
  • Java 高并發(fā)二:多線程基礎(chǔ)詳細(xì)介紹

    Java 高并發(fā)二:多線程基礎(chǔ)詳細(xì)介紹

    本文主要介紹Java 高并發(fā)多線程的知識(shí),這里整理詳細(xì)的資料來解釋線程的知識(shí),有需要的學(xué)習(xí)高并發(fā)的朋友可以參考下
    2016-09-09
  • Java中多態(tài)的實(shí)現(xiàn)原理詳細(xì)解析

    Java中多態(tài)的實(shí)現(xiàn)原理詳細(xì)解析

    這篇文章主要介紹了Java中多態(tài)的實(shí)現(xiàn)原理詳細(xì)解析,多態(tài)是面向?qū)ο缶幊陶Z言的重要特性,它允許基類的指針或引用指向派生類的對(duì)象,而在具體訪問時(shí)實(shí)現(xiàn)方法的動(dòng)態(tài)綁定,需要的朋友可以參考下
    2024-01-01
  • SpringBoot激活profiles的幾種方式

    SpringBoot激活profiles的幾種方式

    多環(huán)境是最常見的配置隔離方式之一,可以根據(jù)不同的運(yùn)行環(huán)境提供不同的配置信息來應(yīng)對(duì)不同的業(yè)務(wù)場(chǎng)景,這篇文章主要介紹了SpringBoot激活profiles的幾種方式,需要的朋友可以參考下
    2019-10-10
  • Spring容器-BeanFactory和ApplicationContext使用詳解

    Spring容器-BeanFactory和ApplicationContext使用詳解

    這篇文章主要為大家介紹了Spring容器-BeanFactory和ApplicationContext的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 解析java.library.path和LD_LIBRARY_PATH的介紹與區(qū)別

    解析java.library.path和LD_LIBRARY_PATH的介紹與區(qū)別

    這篇文章主要介紹了java.library.path和LD_LIBRARY_PATH的介紹與區(qū)別,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • Springboot 中使用 Aop代碼實(shí)戰(zhàn)教程

    Springboot 中使用 Aop代碼實(shí)戰(zhàn)教程

    AOP的編程思想是把對(duì)類對(duì)象的橫切問題點(diǎn),從業(yè)務(wù)邏輯中分離出來,從而達(dá)到解耦的目的,增加代碼的復(fù)用性,提高開發(fā)效率,這篇文章主要介紹了Springboot中使用Aop代碼實(shí)戰(zhàn)教程,需要的朋友可以參考下
    2023-07-07
  • Spring Boot中自定義注解結(jié)合AOP實(shí)現(xiàn)主備庫切換問題

    Spring Boot中自定義注解結(jié)合AOP實(shí)現(xiàn)主備庫切換問題

    這篇文章主要介紹了Spring Boot中自定義注解+AOP實(shí)現(xiàn)主備庫切換的相關(guān)知識(shí),本篇文章的場(chǎng)景是做調(diào)度中心和監(jiān)控中心時(shí)的需求,后端使用TDDL實(shí)現(xiàn)分表分庫,需要的朋友可以參考下
    2019-08-08

最新評(píng)論