简介
说明
本文用示例介绍CountDownLatch的用法。
CountDownLatch也属于JUC。线程可以使用await()进行等待,多线程进行递减计数,等到计数到0的时候等待即不再阻塞,从而向下执行。
在日常开发中经常会遇到需要在主线程中开启多个线程去并行执行任务,并且主线程需要等待所有子线程执行完毕后再进行汇总的场景。
概述
在CountDownLatch出现之前一般都使用线程的join()方法来实现这一点,但是join方法不够灵活,两者的对比如下:
项 | CountDonLatch | join() |
是否适用于线程池 | 适用。 | 不适用。 使用线程池一般是直接添加Runable到线程池,这时没有办法再调用线程的join方法了。 |
调用时机 | 允许子线程运行完毕或者在运行中递减计数。 | 只能等待线程运行完毕。 |
方法
方法名 | 解释 |
void countDown() | 计数器减1 |
long getCount() | 返回当前计数值 |
void await() | 当前线程阻塞,直到该计数器为0后才能继续执行 |
boolean await(long timeout, TimeUnit unit) | 与上述await()类似,只不过可以设置等待时间,如果在规定时间内计数器的值依然大于0,则继续执行 |
实例
简介
描述:创建两个线程,主流程里等待这两个线程都结束,才往下进行。
代码
package org.example.a;
import java.util.concurrent.CountDownLatch;
public class Demo {
// 创建一个CountDownLatch实例
private static volatile java.util.concurrent.CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println("子线程1结束!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}
});
Thread threadTwo = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println("子线程2结束!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}
});
// 启动子线程
threadOne.start();
threadTwo.start();
System.out.println("等待所有子线程结束---");
// 等待子线程执行完毕,返回
countDownLatch.await();
System.out.println("所有子线程结束!");
}
}
测试
等待所有子线程结束---
子线程2结束!
子线程1结束!
所有子线程结束!
包装
描述
上边的实例仅仅是等待结束,没有传递结果,本处将CountdownLatch包装一下,让它传递结果。
单个结果
包装类
package org.example.a;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class SynchroniseUtil<T>{
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private T result;
public T get() throws InterruptedException{
countDownLatch.await();
return this.result;
}
public T get(long timeout, TimeUnit timeUnit) throws Exception{
if (countDownLatch.await(timeout, timeUnit)) {
return this.result;
} else {
throw new RuntimeException("超时");
}
}
public void setResult(T result) {
this.result = result;
countDownLatch.countDown();
}
}
测试类
package org.example.a;
public class Demo {
public static void main(String[] args) throws InterruptedException {
SynchroniseUtil<String> synchroniseUtil = new SynchroniseUtil<>();
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println("子线程1结束!");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
synchroniseUtil.setResult("线程1执行成功");
}
}
});
// 启动子线程
threadOne.start();
System.out.println("等待所有子线程结束---");
// 等待子线程执行完毕,返回
String result = synchroniseUtil.get();
System.out.println("所有子线程结束!");
System.out.println("返回结果:" + result);
}
}
测试
等待所有子线程结束---
子线程1结束!
所有子线程结束!
返回结果:线程1执行成功
多个结果
其他网址
Netty实现同步“请求-响应”的同步通信机制 - SegmentFault 思否
《Java并发编程之美》=> 10.1 CountDownLatch 原理剖析