竹笋

首页 » 问答 » 灌水 » CyclicBarrier傻傻的分
TUhjnbcbe - 2025/2/8 17:12:00

前言

并发编程的三大核心是分工,同步和互斥。在日常开发中,经常会碰到需要在主线程中开启多个子线程去并行的执行任务,并且主线程需要等待所有子线程执行完毕再进行汇总的场景,这就涉及到分工与同步的内容了

在讲有序性可见性,Happens-before来搞定时,提到过join()规则,使用join()就可以简单地实现上述场景:

运行结果:

整个过程可以这么理解

我们来查看join()的实现源码:

其实现原理是不停的检查join线程是否存活,如果join线程存活,则wait(0)永远的等下去,直至join线程终止后,线程的this.notifyAll()方法会被调用(该方法是在JVM中实现的,JDK中并不会看到源码),退出循环恢复主线程执行。很显然这种循环检查的方式比较低效。

除此之外,使用join()缺少很多灵活性,比如实际项目中很少让自己单独创建线程(原因在我会手动创建线程,为什么要使用线程池?中说过)而是使用Executor,这进一步减少了join()的使用场景,所以join()的使用在多数是停留在demo演示上

那如何实现文中开头提到的场景呢?

CountDownLatch

CountDownLatch那肯定里面有计数器的存在了。我们将上述程序用CountDownLatch实现一下,先让大家有个直观印象

运行结果如下:

结合上述示例的运行结果,相信你也能猜出CountDownLatch的实现原理了:

初始化计数器数值,比如为2子线程执行完则调用countDownLatch.countDown()方法将计数器数值减1主线程调用await()方法阻塞自己,直至计数器数值为0(即子线程全部执行结束)不知道你是否注意,countDownLatch.countDown();这行代码可以写在子线程执行的任意位置,不像join()要完全等待子线程执行完,这也是CountDownLatch灵活性的一种体现

上述的例子还是过于简单,官方CountDownLatch说明有两个非常经典的使用场景,示例很简单,强烈建议查看相关示例代码,打开使用思路。我将两个示例代码以图片的形式展示在此处:

1
查看完整版本: CyclicBarrier傻傻的分