首页 > 编程语言 >[Java并发]CountDownLatch

[Java并发]CountDownLatch

时间:2024-07-26 21:07:11浏览次数:13  
标签:count do Java work 并发 something doneSignal CountDownLatch

CountDownLatch概述
CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。
有一点要说明的是CountDownLatch初始化后计数器值递减到0的时候,不能再复原的,这一点区别于Semaphore,Semaphore是可以通过release操作恢复信号量的。
CountDownLatch使用原理
使用原理
创建CountDownLatch并设置计数器值。
启动多线程并且调用CountDownLatch实例的countDown()方法。
主线程调用 await() 方法,这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务,count值为0,停止阻塞,主线程继续执行。
使用模板
public class CountDownLatchModule {

//线程数
private static int N = 10;

// 单位:min
private static int countDownLatchTimeout = 5;

public static void main(String[] args) {
    //创建CountDownLatch并设置计数值,该count值可以根据线程数的需要设置
    CountDownLatch countDownLatch = new CountDownLatch(N);

	//创建线程池
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

    for (int i = 0; i < N; i++) {
        cachedThreadPool.execute(() ->{
            try {
                System.out.println(Thread.currentThread().getName() + " do something!");
            } catch (Exception e) {
                System.out.println("Exception: do something exception");
            } finally {
                //该线程执行完毕-1
                countDownLatch.countDown();
            }
        });
    }

    System.out.println("main thread do something-1");
    try {
        countDownLatch.await(countDownLatchTimeout, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        System.out.println("Exception: await interrupted exception");
    } finally {
        System.out.println("countDownLatch: " + countDownLatch.toString());
    }
    System.out.println("main thread do something-2");
    //若需要停止线程池可关闭;

// cachedThreadPool.shutdown();

}

运行结果:

main thread do something-1
pool-1-thread-1 do something!
pool-1-thread-2 do something!
pool-1-thread-3 do something!
pool-1-thread-5 do something!
pool-1-thread-6 do something!
pool-1-thread-7 do something!
pool-1-thread-8 do something!
pool-1-thread-4 do something!
pool-1-thread-9 do something!
pool-1-thread-10 do something!
countDownLatch: java.util.concurrent.CountDownLatch@76fb509a[Count = 0]
main thread do something-2

CountDownLatch常用方法
在这里插入图片描述

public void await() throws InterruptedException:调用await()方法的线程会被挂起,等待直到count值为0再继续执行。
public boolean await(long timeout, TimeUnit unit) throws InterruptedException:同await(),若等待timeout时长后,count值还是没有变为0,不再等待,继续执行。时间单位如下常用的毫秒、天、小时、微秒、分钟、纳秒、秒。
在这里插入图片描述
public void countDown(): count值递减1.
public long getCount():获取当前count值。
public String toString():重写了toString()方法,多打印了count值,具体参考源码。
CountDownLatch使用场景
一个程序中有N个任务在执行,我们可以创建值为N的CountDownLatch,当每个任务完成后,调用一下countDown()方法进行递减count值,再在主线程中使用await()方法等待任务执行完成,主线程继续执行。

CountDownLatch源码
构造方法源码
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
toString()方法源码
/
*
* Returns a string identifying this latch, as well as its state.
* The state, in brackets, includes the String {@code "Count ="}
* followed by the current count.
*
* @return a string identifying this latch, as well as its state
*/
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
CountDownLatch示例
作为线程启动信号
代码

public class CountDownLatchTest {

/**
 * a start signal that prevents any worker from proceeding
 * until the driver is ready for them to proceed;
 * @param args
 * @throws InterruptedException
 */
public static void main(String[] args) throws InterruptedException {
    CountDownLatch startSignal = new CountDownLatch(1);
    CountDownLatch doneSignal = new CountDownLatch(10);
    for (int i = 0; i < 10; i++) {
        // create and start threads
        new Thread(new Worker(startSignal, doneSignal)).start();
    }
    // don't let run yet
    System.out.println("do something else 1");
    // let all threads proceed
    startSignal.countDown();
    System.out.println("do something else 2");
    // wait for all to finish
    doneSignal.await();
    System.out.println("wait for all to finsh");
}

static class Worker implements Runnable{

    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;

    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

    @Override
    public void run() {
        try {
            startSignal.await();
            doWork();
            doneSignal.countDown();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    void doWork() {
        System.out.println("do work!");
    }
}

}
运行结果

do something else 1
do something else 2
do work!
do work!
do work!
do work!
do work!
do work!
do work!
do work!
do work!
do work!
wait for all to finsh
从运行结果可以看出:

主线程先打印do something else 1和do something else 2。因为startSignal.countDown();完后,count才为0,子线程才能打印。
因为startSignal.await();是在子线程内,所有子线程都等待startSignal.countDown()执行后才能打印do work!。
doneSignal.await();等待所有子线程执行后,每次都doneSignal.countDown(),最后count为0,主线程才执行打印wait for all to finsh。
作为线程等待完成信号
代码

public class CountDownLatchTest2 {

/**
 * a completion signal that allows the driver to wait
 * until all workers have completed.
 * @param args
 * @throws InterruptedException
 */
public static void main(String[] args) throws InterruptedException {
    CountDownLatch doneSignal = new CountDownLatch(5);
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        // create and start threads
        cachedThreadPool.execute(new Worker(doneSignal, i));
    }
    // don't let run yet
    System.out.println("do something else 1");
    // wait for all to finish
    doneSignal.await();
    System.out.println("===========================count: " + doneSignal.getCount());
    System.out.println("do something else 2");
    cachedThreadPool.shutdown();
}

static class Worker implements Runnable{

    private final CountDownLatch doneSignal;
    private final int i;

    Worker(CountDownLatch doneSignal, int i) {
        this.doneSignal = doneSignal;
        this.i = i;
    }

    @Override
    public void run() {
        try {
            doWork();
            doneSignal.countDown();
            System.out.println("i = " + i + ", " + doneSignal.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    void doWork() {
        System.out.println("do work!");
    }
}

}
运行结果

do something else 1
do work!
i = 0, java.util.concurrent.CountDownLatch@128abd43[Count = 4]
do work!
i = 1, java.util.concurrent.CountDownLatch@128abd43[Count = 3]
do work!
i = 2, java.util.concurrent.CountDownLatch@128abd43[Count = 2]
do work!
i = 3, java.util.concurrent.CountDownLatch@128abd43[Count = 1]
do work!
i = 4, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
===========================count: 0
do something else 2
do work!
i = 5, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 6, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 7, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 8, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 9, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
从运行结果可以看出,主线程是等待其他线程运行了5次结束后就打印了do something else 2信息,因为CountDownLatch数值为5。

标签:count,do,Java,work,并发,something,doneSignal,CountDownLatch
From: https://www.cnblogs.com/DCFV/p/18326250

相关文章

  • Java中的ETL工具选型与应用
    Java中的ETL工具选型与应用大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨Java中的ETL(Extract,Transform,Load)工具,帮助你了解如何选择和应用这些工具,以便高效地进行数据提取、转换和加载任务。ETL工具在数据工程和大数据处理中扮......
  • java多线程把数据迁移到不同数据库中
    publicvoidsync_table_test_thread()throwsSQLException,InterruptedException{    longstart=System.currentTimeMillis();    SimpleDateFormatformat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");    //获取要迁移oracle表数据库......
  • 学习Java的第十一天啦(2024.7.26)
    1.死锁的条件:死锁的产生还涉及到一些具体的条件,这些条件可以被看作是死锁产生的必要条件,包括:1.互斥条件:资源不能被多个进程或线程同时访问,即资源是互斥的。2.请求保持条件:进程或线程在请求资源时,已经持有其他资源,并且不愿意释放已经持有的资源。3.不可剥夺条件:已经分配给进......
  • [Java基础]Finally
    finally中的代码一定会执行吗?通常在面试中,只要是疑问句一般答案都是“否定”的,因为如果是“确定”和“正常”的,那面试官就没有必要再问了嘛,而今天这道题的答案也是符合这个套路。1.典型回答正常运行的情况下,finally中的代码是一定会执行的,但是,如果遇到以下异常情况,那么finall......
  • JAVA集中学习第二周学习记录(四)
    系列文章目录第一章JAVA集中学习第一周学习记录(一)第二章JAVA集中学习第一周项目实践第三章JAVA集中学习第一周学习记录(二)第四章JAVA集中学习第一周课后习题第五章JAVA集中学习第二周学习记录(一)第六章JAVA集中学习第二周项目实践第七章JAVA集中学习第二......
  • [Java面向对象]final
    final简介[2]final关键字可用于多个场景,且在不同场景具有不同的作用。首先,final是一个非访问修饰符,仅适用于变量,方法或类。下面是使用final的不同场景:java中的final关键字上面这张图可以概括成:当final修饰变量时,被修饰的变量必须被初始化(赋值),且后续不能修改其值,实质上是常......
  • JAVA集中学习第二周项目实践[图书管理系统]
    系列文章目录第一章JAVA集中学习第一周学习记录(一)第二章JAVA集中学习第一周项目实践第三章JAVA集中学习第一周学习记录(二)第四章JAVA集中学习第一周课后习题第五章JAVA集中学习第二周学习记录(一)第六章JAVA集中学习第二周项目实践文章目录系列文章目录......
  • [Java并发]
    多线程的价值(这里展示的是网上的答案,我觉得真正重要的是减少进程切换的代价)发挥多核CPU的优势多线程,可以真正发挥出多核CPU的优势来,达到充分利用CPU的目的,采用多线程的方式去同时完成几件事而不互相干扰。防止阻塞从程序运行效率的角度来看,单核CPU不但不会发挥出多线程的......
  • java位运算
    位运算符:针对二进制的值补码形式进行计算的&|^(相同为0,不同为1)~<<>>>>>publicclassWeiOptDemo1{publicstaticvoidmain(String[]args){bytea1=3;byteb1=4;System.out.println(a1&b1);System.out.println(a1|b1);System.o......
  • Go语言---并发版网页段子筛选爬虫
    爬虫四个主要步骤:明确目标(要知道你准备在哪个范围或者网站去搜索爬(将所有的网站的内容全部爬下来)取(去掉对我们没用处的数据)处理数据(按照我们想要的方式存储和使用)在此之前,我们实现的简单版以及并发版的爬虫都没有对我们所需的信息进行过滤,这样得到的信息大多是我......