概述
- CyclicBarrie允许让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
- CyclicBarrier只能唤起一个任务,CountDownLatch可以同时唤起多个任务
- CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了
方法摘要
CyclicBarrie有两个构造方法,CyclicBarrier(int parties)创建一个新的CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。CyclicBarrier(int parties, Runnable barrierAction)多了一个传入的屏障被唤醒时指定优先执行的方法,该操作由最后一个进入 barrier 的线程执行。await()在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。await(long timeout, TimeUnit unit)在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。int getNumberWaiting()返回当前在屏障处等待的参与者数目。int getParties()返回要求启动此 barrier 的参与者数目。boolean isBroken()查询此屏障是否处于损坏状态。void reset()将屏障重置为其初始状态。如何使用
1 | public class CyclicBarrierTest { |
输出
1 | Thread-0:开始处理表格数据 |
源码分析
初始化
1 | /** 重入 */ |
可以看出屏障计数器不能为0 。内部是依赖重入锁ReentrantLock和Condition实现的,这点和CountDownLatch不一样。
await()方法
1 | public int await() throws InterruptedException, BrokenBarrierException { |
await()
方法主要依靠dowait`方法时u,会让线程会到达屏障点时一直处于等待中
1 | private int dowait(boolean timed, long nanos) |
- 当线程调用
await方法,首先会拿到ReentrantLock重入锁执行加锁操作,然后判断是否有线程执行了中断操作,如果有则抛出异常,没有就继续向下执行,把屏障计数器做递减操作,然后判断这个屏障计数器是否为0 ,如果递减后的计数器等于0,则表明所有线程都已到达屏障点。 - 然后判断是否有传入指定的优先执行任务,如果有则先启动这个任务,然后唤醒所有等待的线程,重置屏障计数器
count和Generation - 如果屏障值不为0,则执行一个死循环,也就是自选操作。自选操作中,会先判断是否制定了超时等待时间,如果没有指定就执行
Condition的await方法,让线程一直处于等待中,除非被唤醒或有其它线程执行了中断CyclicBarrier操作。 - 如果制定了超时等待时间,则执行
Condition的超时等待方法,让线程一直处于等待中,除非被唤醒或到达超时等待时间
总结
CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了这个点,所有线程才重新运行;CountDownLatch则不是,某线程运行到某个点上之后,只是给某个数值-1而已,该线程继续运行CyclicBarrier只能唤起一个任务,CountDownLatch可以唤起多个任务CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了CountDownLatch内部是基于AQS队列同步器实现,CyclicBarrier基于ReentrantLock和Condition实现等待机制和唤醒的
