一、CyclicBarrier
CyclicBarrier拥有CountDownLatch的功能(CountDownLatch的介绍请看我的另一篇博客: Java并发编程——Semaphore (信号量)和CountDownLatch ),任何一个线程在没有完成时,所有线程都在等待。有点类似于屏障的意思,比如百米赛跑,需要等所有运动员都到达起跑线后,裁判才会鸣枪,这个“起跑线”就是屏障,每个运动员就是一个个线程,而“裁判鸣枪”就是后需要做的一些事情。
上栗子:
public static void main(String[] args) {
final CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
//执行所有线程全部完成后的逻辑
try {
System.out.println("执行所有线程全部完成后的逻辑 开始");
Thread.sleep(3000);
System.out.println("执行所有线程全部完成后的逻辑 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//子线程数量
int threadNum = 4;
for (int i = 0; i < threadNum; i++) {
final int finalI = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始" + finalI);
cyclicBarrier.await();
System.out.println("结束" + finalI);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}).start();
}
}
简单粗暴,直接看log:
12-19 15:19:28.470 18459-18635/? I/System.out: 开始0
12-19 15:19:28.470 18459-18636/? I/System.out: 开始1
12-19 15:19:28.470 18459-18637/? I/System.out: 开始2
12-19 15:19:28.470 18459-18638/? I/System.out: 开始3
接下来改变线程数量:
//子线程数量
int threadNum = 5;
再次运行看log:
12-19 15:22:27.810 22580-22713/lbx.myapplication I/System.out: 开始0
12-19 15:22:27.810 22580-22715/lbx.myapplication I/System.out: 开始2
12-19 15:22:27.810 22580-22714/lbx.myapplication I/System.out: 开始1
12-19 15:22:27.810 22580-22716/lbx.myapplication I/System.out: 开始3
12-19 15:22:27.820 22580-22717/lbx.myapplication I/System.out: 开始4
12-19 15:22:27.820 22580-22717/lbx.myapplication I/System.out: 执行所有线程全部完成后的逻辑 开始
//睡了三秒
12-19 15:22:30.820 22580-22717/lbx.myapplication I/System.out: 执行所有线程全部完成后的逻辑 结束
12-19 15:22:30.820 22580-22717/lbx.myapplication I/System.out: 结束4
12-19 15:22:30.820 22580-22713/lbx.myapplication I/System.out: 结束0
12-19 15:22:30.820 22580-22715/lbx.myapplication I/System.out: 结束2
12-19 15:22:30.820 22580-22714/lbx.myapplication I/System.out: 结束1
12-19 15:22:30.820 22580-22716/lbx.myapplication I/System.out: 结束3
常用方法:
//在此方法处线程阻塞,n个线程都执行await()后回调Runnable里的逻辑
cyclicBarrier.await();
//阻塞到3秒后则抛出TimeoutException异常,不会继续向下执行
cyclicBarrier.await(3, TimeUnit.SECONDS);
//获得到达await()(屏障)的线程的数量
cyclicBarrier.getNumberWaiting();
//当前线程的屏障是否出现损坏,例如终止线程的时候
cyclicBarrier.isBroken();
//获取屏障的数量:n
cyclicBarrier.getParties();
//重置屏障
cyclicBarrier.reset();
二、Phaser
与CyclicBarrier功能重叠,任何一个线程在没有完成时,所有线程都在等待。
public static void main(String[] args) {
final Phaser phaser = new Phaser(5) {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
//当所有线程都完成了一个任务的时候,会回调。
System.out.println("完成了第" + phase + "个屏障");
//true:后面的屏障无效。false:保持屏障的有效性
return false;
}
};
//线程数量
int threadNum = 5;
for (int i = 0; i < threadNum; i++) {
final int finalI = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("开始" + finalI);
Thread.sleep(1000);
//与CyclicBarrier相同,都是等待所有线程到达屏障后,再统一释放
phaser.arriveAndAwaitAdvance();
System.out.println("结束" + finalI);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
重写了onAdvance方法,该方法在所有线程执行arriveAndAwaitAdvance后调用。看下log:
12-19 16:28:13.310 16518-16709/lbx.myapplication I/System.out: 开始0
12-19 16:28:13.310 16518-16710/lbx.myapplication I/System.out: 开始1
12-19 16:28:13.310 16518-16711/lbx.myapplication I/System.out: 开始2
12-19 16:28:13.320 16518-16712/lbx.myapplication I/System.out: 开始3
12-19 16:28:13.320 16518-16713/lbx.myapplication I/System.out: 开始4
12-19 16:28:14.320 16518-16713/lbx.myapplication I/System.out: 完成了第0个屏障
12-19 16:28:14.320 16518-16709/lbx.myapplication I/System.out: 结束0
12-19 16:28:14.320 16518-16713/lbx.myapplication I/System.out: 结束4
12-19 16:28:14.320 16518-16710/lbx.myapplication I/System.out: 结束1
12-19 16:28:14.320 16518-16711/lbx.myapplication I/System.out: 结束2
12-19 16:28:14.320 16518-16712/lbx.myapplication I/System.out: 结束3
接下来我们把线程的数量翻倍:
//线程数量
int threadNum = 10;
再次运行,看log:
12-19 16:32:56.440 23790-25143/lbx.myapplication I/System.out: 开始0
12-19 16:32:56.440 23790-25144/lbx.myapplication I/System.out: 开始1
12-19 16:32:56.440 23790-25145/lbx.myapplication I/System.out: 开始2
12-19 16:32:56.440 23790-25146/lbx.myapplication I/System.out: 开始3
12-19 16:32:56.440 23790-25147/lbx.myapplication I/System.out: 开始4
12-19 16:32:56.440 23790-25148/lbx.myapplication I/System.out: 开始5
12-19 16:32:56.440 23790-25149/lbx.myapplication I/System.out: 开始6
12-19 16:32:56.440 23790-25150/lbx.myapplication I/System.out: 开始7
12-19 16:32:56.440 23790-25151/lbx.myapplication I/System.out: 开始8
12-19 16:32:56.440 23790-25152/lbx.myapplication I/System.out: 开始9
12-19 16:32:57.440 23790-25146/lbx.myapplication I/System.out: 完成了第0个屏障
12-19 16:32:57.440 23790-25145/lbx.myapplication I/System.out: 结束2
12-19 16:32:57.440 23790-25146/lbx.myapplication I/System.out: 结束3
12-19 16:32:57.440 23790-25147/lbx.myapplication I/System.out: 结束4
12-19 16:32:57.440 23790-25144/lbx.myapplication I/System.out: 结束1
12-19 16:32:57.440 23790-25143/lbx.myapplication I/System.out: 结束0
12-19 16:32:57.440 23790-25152/lbx.myapplication I/System.out: 完成了第1个屏障
12-19 16:32:57.440 23790-25152/lbx.myapplication I/System.out: 结束9
12-19 16:32:57.440 23790-25149/lbx.myapplication I/System.out: 结束6
12-19 16:32:57.440 23790-25150/lbx.myapplication I/System.out: 结束7
12-19 16:32:57.440 23790-25148/lbx.myapplication I/System.out: 结束5
12-19 16:32:57.440 23790-25151/lbx.myapplication I/System.out: 结束8
因为onAdvance返回的是false,第一次执行过onAdvance后,屏障依然有效,所以后面的代码正常执行,当我们把onAdvance返回true的时候,仍然用10条子线程:
final Phaser phaser = new Phaser(5) {
@Override
protected boolean onAdvance(int phase, int registeredParties) {
//当所有线程都完成了一个任务的时候,会回调。
System.out.println("完成了第" + phase + "个屏障");
//true:后面的屏障无效。false:保持屏障的有效性
return true;
}
};
运行代码,看log:
12-19 16:35:19.050 27494-28566/lbx.myapplication I/System.out: 开始0
12-19 16:35:19.050 27494-28568/lbx.myapplication I/System.out: 开始2
12-19 16:35:19.050 27494-28567/lbx.myapplication I/System.out: 开始1
12-19 16:35:19.050 27494-28569/lbx.myapplication I/System.out: 开始3
12-19 16:35:19.050 27494-28570/lbx.myapplication I/System.out: 开始4
12-19 16:35:19.050 27494-28571/lbx.myapplication I/System.out: 开始5
12-19 16:35:19.050 27494-28572/lbx.myapplication I/System.out: 开始6
12-19 16:35:19.050 27494-28573/lbx.myapplication I/System.out: 开始7
12-19 16:35:19.050 27494-28574/lbx.myapplication I/System.out: 开始8
12-19 16:35:19.050 27494-28575/lbx.myapplication I/System.out: 开始9
12-19 16:35:20.050 27494-28570/lbx.myapplication I/System.out: 完成了第0个屏障
12-19 16:35:20.050 27494-28570/lbx.myapplication I/System.out: 结束4
12-19 16:35:20.050 27494-28568/lbx.myapplication I/System.out: 结束2
12-19 16:35:20.050 27494-28571/lbx.myapplication I/System.out: 结束5
12-19 16:35:20.050 27494-28566/lbx.myapplication I/System.out: 结束0
12-19 16:35:20.050 27494-28567/lbx.myapplication I/System.out: 结束1
12-19 16:35:20.050 27494-28572/lbx.myapplication I/System.out: 结束6
12-19 16:35:20.050 27494-28569/lbx.myapplication I/System.out: 结束3
12-19 16:35:20.050 27494-28573/lbx.myapplication I/System.out: 结束7
12-19 16:35:20.050 27494-28574/lbx.myapplication I/System.out: 结束8
12-19 16:35:20.050 27494-28575/lbx.myapplication I/System.out: 结束9
我们发现,onAdvance只执行了一次,因为反悔了true,使屏障无效了,那么也就没有屏障的概念了。
常用方法:
//获得当前parties的个数
phaser.getRegisteredParties();
//使parties的个数加1
phaser.register();
//使parties的个数加3
phaser.bulkRegister(3);
//获得当前已经被使用的parties的个数
phaser.getArrivedParties();
//获得当前未被使用的parties的个数
phaser.getUnarrivedParties();
//使parties的个数加1,并继续往下执行,回调onAdvance()方法
phaser.arrive();
//若传入的参数与getPhase()的值一样,则处于屏障阻塞状态,否则继续往下执行过。该方法不参与计算,只起判断作用
phaser.awaitAdvance(3);