如果有遗漏,评论区告诉我进行补充
CyclicBarrierCountDownLatch_1">面试官: 说说CyclicBarrier和CountDownLatch的区别?
我回答:
在Java高级面试中,CyclicBarrier和CountDownLatch是两个经常被提及的并发工具类,它们都用于实现线程间的同步,但存在显著的区别。以下是对这两个类的详细比较:
一、计数器使用方式的区别
-
- 是一个减法计数器。
- 计数器一旦初始化,只能递减,不能重置或增加。
- 当计数器的值减至零时,所有因调用await()方法而被阻塞的线程会被唤醒,继续执行。
-
- 可以理解为加法计数器,但其实际工作机制并非简单的加法。
- 计数器可以重复使用,通过reset()方法重置。
- 当指定数量的线程都调用了await()方法时,这些线程会被同时唤醒,继续执行。此时,计数器会重置为初始值,以便下一轮使用。
二、等待和继续执行的方式
-
- 主要用于一个或多个线程等待其他线程完成某项任务。
- 只有当所有需要等待的线程都完成任务(即计数器减至零),被阻塞的线程才能继续执行。
-
- 用于一组线程互相等待,直到所有线程都到达某个公共屏障点。
- 一旦所有线程都到达屏障点,它们会同时被唤醒并继续执行。
- 由于CyclicBarrier的计数器可以重置,因此它适用于需要多次等待和同步的场景。
三、异常处理
-
- 计数器的递减操作(countDown())可能会抛出异常,但这些异常不会影响其他线程的执行。
-
- 在调用await()方法时可能会抛出异常(如BrokenBarrierException),此时需要使用try-catch块来捕获和处理这些异常。
四、主要区别
是否可复用
-
CountDownLatch
:不可复用。一旦计数值达到了0,该CountDownLatch
就不能再被重置或再次使用。 -
CyclicBarrier
:可复用。每当所有线程都到达屏障点后,它可以自动重置并重新开始计数,以便下一轮的线程再次等待。
初始化参数
CountDownLatch
:仅需指定一个初始计数值,代表需要等待的事件数量。CyclicBarrier
:除了指定参与者数量外,还可以提供一个Runnable
对象作为屏障动作(barrier action),这个动作会在所有线程到达屏障点之后、但在任何线程继续执行之前被执行。
等待行为
-
CountDownLatch
:主线程或其他线程可以通过await()
方法等待,直到计数值变为0。 -
CyclicBarrier
:每个线程通过await()
方法等待,直到所有线程都到达屏障点;如果某个线程提前离开(例如因为异常),则其他线程会抛出BrokenBarrierException
。
超时机制
-
CountDownLatch
:没有内置的超时机制,但如果使用带超时参数的await(long timeout, TimeUnit unit)
方法,则可以在指定时间内尝试等待。 -
CyclicBarrier
:支持带超时的await(long timeout, TimeUnit unit)
方法,允许设置最大等待时间,超过此时间如果没有所有线程到达屏障点,则抛出TimeoutException
。
五、使用场景
-
- 适用于主线程等待所有子线程完成任务后再继续执行的场景。
- 适用于统计多个线程执行时间的场景。
-
- 适用于多个线程需要互相等待,并在某个公共点上同步执行的场景。
- 适用于需要多次等待和同步的周期性任务场景。