CountDownLatch概述
- 阻塞当前线程功能;
- 初始化的时候指定了计数器的值,多线程对计数器的值的操作是原子性的,同时只能有一个线程操作其中计数器的值;
- 调用该类的await()方法的线程会一直处于阻塞状态,直到其他线程调用countDown(),将当前计数器的值减为0,每次调用countDown()的时候,计数器的值减1,当计数器的值减为0时,所有因调用await()方法而阻塞的线程都会继续执行;
- 其中计数器的值是不能被重置的,如果是需要重置计数器的版本,可以考虑CyclicBarrier;
CountDownLatch使用场景
- 程序需要等待某个条件完成后,才能继续执行,典型运用比如:并行计算,当某个处理的值很大时,可以将该运算任务拆成多个子任务,等到所有子任务运算完成后,父任务拿到所有子任务的运算结果进行汇总;
CountDownLatch示例(一)
- CountDownLatch使用步骤
- 初始化时指定计数器的值;
- 前置线程中记得调用countDownLatch.countDown()方法;
- 主线程(后置线程)要调用countDownLatch.await()等待前置线程运行完成;
- 如果countDownLatch.countDown()是一定要执行的,可以放在finally中,以防程序抛出异常是可能执行;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class CountDownLatchExample1 {
private final static int threadCount = 200;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
test(threadNum);
} catch (Exception e) {
log.error("exception", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
log.info("finish");
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
log.info("{}", threadNum);
Thread.sleep(100);
}
}
CountDownLatch示例(一)规定等待时间
- countDownLatch.await(10, TimeUnit.MILLISECONDS)如果指定了等待时间,则主线程的执行不依赖于前置线程都执行完成,即不依赖于countDownLatch中的计数器减为0;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
public class CountDownLatchExample2 {
private final static int threadCount = 200;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
test(threadNum);
} catch (Exception e) {
log.error("exception", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await(10, TimeUnit.MILLISECONDS);
log.info("finish");
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
log.info("{}", threadNum);
}
}