CyclicBarrier和CountDownLatch是Java并发工具类,并且平时很多场景都会使用到,本文详解两者的原理和区别@mikechen
CountDownLatch原理
CountDownLatch简介
CountDownLatch就是一个或者一组线程在开始执行操作之前,必须要等到其他线程执行完才可以。
例如:应用程序的主线程,希望在负责启动框架服务的线程,启动所有的框架服务之后,最后再执行。
例如倒数计时器:一种典型的场景就是火箭发射,在火箭发射前,为了保证万无一失,往往还要进行各项设备、仪器的检查。
除了刚提到的技术场景,生活中场景也是非常多的,比如:在考试的时候,老师必须要等到所有人交了试卷才可以走。
以上这些场景,都是非常适合使用CountDownLatch的。
CountDownLatch实现原理
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。
每当一个线程完成了自己的任务后,计数器的值就会减1,当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
如下图所示:
整个的实现步骤,大致可以分为如下3步:
第一步:初始计数器
// 等待线程的数量为10 CountDownLatch c = new CountDownLatch(10);
第二步:主线程阻塞
此时,主线程调用CountDownLatch的await()方法,阻塞当前线程(即:主线程在闭锁上等待),直到计数器的值为0。
//主线程在闭锁上等待,直到计数器的值为0 countDownLatch.await()
第三步:计数器减1
主线程闭锁等待后,子线程开始执行任务,每当一个线程完成了自己的任务后,调用CountDownLatch的countDown()方法,计数器的值就会减1,如下所示:
//countDown():计数器减一,表示线程完成任务 CountDownLatch.countDown()
上面的初始线程10陆续减完,当计数器值到达0时,它表示所有的线程已经完成了任务,此时,在闭锁上等待的主线程就可以恢复执行任务。
CyclicBarrier
CyclicBarrier简介
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier),它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,它也是AQS多线程同步操作的一个具体实现。
CyclicBarrier的实现原理
而 CyclicBarrier 基于 Condition 来实现的,在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用await方法将自己阻塞,此时计数器会减1,当计数器减为0的时候所有因调用await方法而被阻塞的线程将被唤醒。
如下图所示:
CountDownLatch和CyclicBarrier区别
- CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,CyclicBarrier 可以循环利用;
- CountDownLatch 的计数是减 1 直到 0,CyclicBarrier 是加 1,直到指定值。
- CountDownLatch 是一个线程等待其他线程, CyclicBarrier 是多个线程互相等待;
- CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程;
- CountDownLatch 放行由其他线程控制而CyclicBarrier是由本身来控制的。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》