您的位置:首页 > 编程语言 > Java开发

java多线程解说【拾陆】_并发工具类:CyclicBarrier

2018-02-26 16:53 881 查看
上篇文章:java多线程解说【拾伍】_并发工具类:CountDownLatch

上文中我们介绍了CountDownLatch的使用,而且知道CountDownLatch是不支持重复使用的。那么如果我们想重复使用,就需要用到下面要介绍的CyclicBarrier了。

CyclicBarrier

顾名思义,CyclicBarrier的意思就是循环(Cyclic)屏障(Barrier)。它可以实现,让一组线程达到一个屏障后阻塞,直到最后一个线程达到屏障后,屏障才会释放,该组线程得以一起执行。重要的是当屏障才会释放以后下次还可以使用。

CyclicBarrier的默认构造方法是

CyclicBarrier(int parties)


参数为屏障阻拦的线程数量。每个线程用CyclicBarrier.await()方法告诉CyclicBarrier已到达屏障,然后线程被阻塞。直到被阻塞的线程数达到parties时,线程再统一执行。

一个例子

public class TestCyclicBarrier {

public static void main(String[] args) {
int n = 4;
CyclicBarrier barrier  = new CyclicBarrier(n);

for(int i=0;i<n;i++) {
new TestWriter(barrier).start();
}

try {
Thread.sleep(25000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("CyclicBarrier重用");

for(int i=0;i<n;i++) {
new TestWriter(barrier).start();
}
}
static class TestWriter extends Thread{

private CyclicBarrier cyclicBarrier;

public TestWriter(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}

@Override
public void run() {

System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");

try {
Thread.sleep(5000);
System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
}catch(BrokenBarrierException e){
e.printStackTrace();
}

System.out.println(Thread.currentThread().getName()+"所有线程写入完毕,继续处理其他任务...");
}
}

}


常用API

CyclicBarrier(int parties)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。

int await()
在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
int await(long timeout, TimeUnit unit)
在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
int getNumberWaiting()
返回当前在屏障处等待的参与者数目。
int getParties()
返回要求启动此 barrier 的参与者数目。
boolean isBroken()
查询此屏障是否处于损坏状态。
void reset()
将屏障重置为其初始状态。

实现分析

CyclicBarrier是通过ReentrantLock(独占锁)和Condition来实现的,其内部还维护了必须同时到达barrier的线程个数parties和待触发执行的动作Runnable barrierAction。

await()的作用就是先让当前线程阻塞,然后将CyclicBarrier内部记录还需等待的线程数count-1,判断count是否为0,若为0则意味着有parties个线程到达barrier,当前线程才可以继续执行。除了上面情况,当当前线程被中断和超时二者之一发生,当前线程也可能继续执行。方法中的逻辑都是在独占锁的lock范围内进行的。

在CyclicBarrier中,还有一个Generation对象用于标注线程,同一批的线程属于同一代(Generation)。当有parties个线程到达barrier,generation就会被更新换代。

CountDownLatch和CyclicBarrier的区别

CountDownLatch的计数器只能用一次,而CyclicBarrier的计数器可以通过reset()方法重置继续使用。

CyclicBarrier还支持一些使用的方法用于定位问题,如:

getNumberWaiting

获取CyclicBarrier的阻塞线程数量

isBroken

了解阻塞的线程是否被中断

下篇文章:java多线程解说【拾柒】_并发工具类:Semaphore
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: