文章插图
(3)CountDownLatch和CyclicBarrierCountDownLatch 和 CyclicBarrier 类似,都是等待所有任务到达某个点之后,再进行后续的操作,如下图所示:
文章插图
CountDownLatch 使用的示例代码如下:
【如何判断线程池任务已执行完?】
public static void main(String[] args) throws InterruptedException {// 创建线程池ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 20,0, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1024));final int taskCount = 5;// 任务总数// 单次计数器CountDownLatch countDownLatch = new CountDownLatch(taskCount); // ①// 添加任务for (int i = 0; i < taskCount; i++) {final int finalI = i;threadPool.submit(new Runnable() {@Overridepublic void run() {try {// 随机休眠 0-4sint sleepTime = new Random().nextInt(5);TimeUnit.SECONDS.sleep(sleepTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(String.format("任务%d执行完成", finalI));// 线程执行完,计数器 -1countDownLatch.countDown();// ②}});}// 阻塞等待线程池任务执行完countDownLatch.await();// ③// 线程池执行完System.out.println();System.out.println("线程池任务执行完成!");}
代码说明:以上代码中标识为 ①、②、③ 的代码行是核心实现代码,其中:① 是声明一个包含了 5 个任务的计数器;② 是每个任务执行完之后计数器 -1;③ 是阻塞等待计数器 CountDownLatch 减为 0,表示任务都执行完了,可以执行 await 方法后面的业务代码了 。以上程序的执行结果如下:
文章插图
缺点分析CountDownLatch 缺点是计数器只能使用一次,CountDownLatch 创建之后不能被重复使用 。CyclicBarrier 和 CountDownLatch 类似,它可以理解为一个可以重复使用的循环计数器,CyclicBarrier 可以调用 reset 方法将自己重置到初始状态,CyclicBarrier 具体实现代码如下:
public static void main(String[] args) throws InterruptedException {// 创建线程池ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 20,0, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1024));final int taskCount = 5;// 任务总数// 循环计数器 ①CyclicBarrier cyclicBarrier = new CyclicBarrier(taskCount, new Runnable() {@Overridepublic void run() {// 线程池执行完System.out.println();System.out.println("线程池所有任务已执行完!");}});// 添加任务for (int i = 0; i < taskCount; i++) {final int finalI = i;threadPool.submit(new Runnable() {@Overridepublic void run() {try {// 随机休眠 0-4sint sleepTime = new Random().nextInt(5);TimeUnit.SECONDS.sleep(sleepTime);System.out.println(String.format("任务%d执行完成", finalI));// 线程执行完cyclicBarrier.await(); // ②} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}});}}
以上程序的执行结果如下:文章插图
方法说明CyclicBarrier 有 3 个重要的方法:
- 构造方法:构造方法可以传递两个参数,参数 1 是计数器的数量 parties,参数 2 是计数器为 0 时,也就是任务都执行完之后可以执行的事件(方法) 。
- await 方法:在 CyclicBarrier 上进行阻塞等待,当调用此方法时 CyclicBarrier 的内部计数器会 -1,直到发生以下情形之一:
- 在 CyclicBarrier 上等待的线程数量达到 parties,也就是计数器的声明数量时,则所有线程被释放,继续执行 。
- 当前线程被中断,则抛出 InterruptedException 异常,并停止等待,继续执行 。
- 其他等待的线程被中断,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行 。
- 其他等待的线程超时,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行 。
- 其他线程调用 CyclicBarrier.reset() 方法,则当前线程抛出 BrokenBarrierException 异常,并停止等待,继续执行 。
- reset 方法:使得CyclicBarrier回归初始状态,直观来看它做了两件事:
- 如果有正在等待的线程,则会抛出 BrokenBarrierException 异常,且这些线程停止等待,继续执行 。
- 将是否破损标志位 broken 置为 false 。
推荐阅读
- 数智商业技术2.0时代的新「三驾马车」,阿里妈妈郑波谈如何把握生成式大模型
- Spring容器原始Bean是如何创建的?
- 如何有效跑步才能瘦腿?
- 从低迷开局到剑指24亿,《封神》票房如何起死回生?
- 合装纯牛奶怎么加热可不可以带盒子加热 盒装纯牛奶如何加热
- 怎么嫁接多色月季 嫁接多色月季如何搭配的品种
- 如何逼自己瘦下来?8个方法让你从168瘦到104斤
- 冬季如何有效防静电 冬季防静电小妙招
- 麻辣香锅在家怎么做 麻辣香锅在家如何做
- 荷兰豆肉松焖面的做法 如何做荷兰豆肉松焖面