【Java并发010】使用层面:发令枪CountDownLatch全解析

2023-02-12,,,,

一、前言

CountDownLatch是在java1.5被引入,存在于java.util.cucurrent包中,跟它一起被引入的工具类还有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。

二、CountDownLatch概要

CountDownLatch类作用:使一个线程等待其他线程各自执行完毕后再执行。

CountDownLatch三步操作

    构造函数:它是通过一个计数器来实现的,计数器的初始值是线程的数量;
    减一操作:每当一个线程执行完毕后,计数器的值就-1;
    阻塞通过:当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

CountDownLatch发令枪的意义:让所有线程启动后一起执行,不会先启动的先执行。
CountDownLatch发令枪的实现:构造函数确定数量、countDown减一操作、await全部为0发令启动。

三、CountDownLatch源码解析

CountDownLatch类中只提供了一个构造器:

//参数count为计数值
public CountDownLatch(int count) { };

类中有三个方法是最重要的:

//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//将count值减1
public void countDown() { };

小结,一定要调用的方法是:构造函数、countDown、await。

四、CountDownLatch普通示例(涉及的方法:构造函数、countDown、await)

public class CountDownLatchTest {

    public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(2); // 初始数量为2
System.out.println("主线程开始执行…… ……");
//第一个子线程执行
ExecutorService es1 = Executors.newSingleThreadExecutor();
es1.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println("子线程:"+Thread.currentThread().getName()+"执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
});
es1.shutdown(); //第二个子线程执行
ExecutorService es2 = Executors.newSingleThreadExecutor();
es2.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程:"+Thread.currentThread().getName()+"执行");
latch.countDown();
}
});
es2.shutdown();
System.out.println("等待两个线程执行完毕…… ……");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("两个子线程都执行完毕,继续执行主线程");
}
}

运行结果:

主线程开始执行…… ……
等待两个线程执行完毕…… ……
子线程:pool-1-thread-1执行
子线程:pool-2-thread-1执行
两个子线程都执行完毕,继续执行主线程

五、CountDownLatch并发示例(涉及的方法:构造函数、countDown、await)

public class Parallellimit {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
CountDownLatch cdl = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
CountRunnable runnable = new CountRunnable(cdl); // 设置CountRunnable类中countDownLatch变量的数据为100
pool.execute(runnable);
}
}
} class CountRunnable implements Runnable {
private CountDownLatch countDownLatch;
public CountRunnable(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
synchronized (countDownLatch) {
/*** 每次减少一个容量*/
countDownLatch.countDown();
System.out.println("thread counts = " + (countDownLatch.getCount()));
}
countDownLatch.await();
System.out.println("concurrency counts = " + (100 - countDownLatch.getCount()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

运行结果:

thread counts = 99
thread counts = 98
thread counts = 97
thread counts = 96
thread counts = 95
thread counts = 94
......
thread counts = 6
thread counts = 5
thread counts = 4
thread counts = 3
thread counts = 2
thread counts = 1
thread counts = 0
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100
concurrency counts = 100

CountDownLatch和CyclicBarrier区别:

    countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
    CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用

六、面试金手指

6.1 CountDownLatch

countDownLatch定义:使一个线程等待其他线程各自执行完毕后再执行。
countDownLatch一定要调用的方法: 构造函数、countDown、await

    构造函数中确定数量
    countDown减一操作
    await一定要等到构造函数中设置的count=0才放开阻塞

发令枪CountDownLatch的意义:让所有线程启动后一起执行,不会先启动的先执行。
发令枪CountDownLatch的实现:构造函数确定数量、countDown减一操作、await全部为0发令启动

6.2 面试问题:如何控制十个线程依次输出1~10?

问题:如何控制十个线程依次输出1~10?
回答:

    联合线程,join,线程嵌套的方式;
    线程通信,synchronized+标志位+wait()+notify()/notifyAll() 或者 lock锁+标志位+condition.await()+condition.signal()/signalAll()

七、小结

使用层面:发令枪CountDownLatch全解析,完成了。

天天打码,天天进步!!!

【Java并发010】使用层面:发令枪CountDownLatch全解析的相关教程结束。

《【Java并发010】使用层面:发令枪CountDownLatch全解析.doc》

下载本文的Word格式文档,以方便收藏与打印。