如果有了解过 CountDownLatch 的话,这个应该不难理解,相当于 CountDownLatch 的升级版,使得栅栏可重复使用,下面讲讲大概意思和用法
- 内部有一个计数器,用于记录剩下还没就绪的线程数量
- 内部使用的是 ReentrantLock ,相当于对 ReentrantLock 作了封装
- 和 CountDownLatch 的无别在于,CountDownLatch 是一个线程等待其他线程完成,CyclicBarrier 是多个线程互相等待;CountDownLatch 的计数器只能用一次,CyclicBarrier 可以多次使用
- 主要的 api 只有 await() 这个方法,调用这个方法时,CyclicBarrier 中的计数器会减少,调用这个方法的线程会被阻塞,直到计数器为 0,所有被阻塞的线程会一起放行
- 想要提高并发量的话用这个可以,等于水库积攒水,够了放一波出来
- 要注意栅栏计数器 count 的数量和调用 await() 方法的线程数量是否一致,如果 count > await(),永远无法集合完成,会一直阻塞;而 count < await() 并且 await() 不是 count 的整数倍呢?剩下的,哈哈哈哈,想想 ︿( ̄︶ ̄)︿
- 下面看原理图
用法:
一,作为单一栅栏使用,等待所有线程到齐再往下
public class TestCyclicBarrier {
private static CyclicBarrier barrier;
private static SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
static class GatherAction implements Runnable {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 到达, 等待其他线程到齐");
barrier.await(); //开始拦截线程,等待所有线程到齐才往下
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 开始工作");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
barrier = new CyclicBarrier(10); // 设定计数器计数为 10
Thread[] threads = new Thread[10];// 开启 10 个线程
GatherAction action = new GatherAction(); // 实例化 Runnable 对象
for (int i = 0; i < threads.length; i++) threads[i] = new Thread(action, "线程 " + i);
for (int i = 0; i < threads.length; i++) threads[i].start();
for (int i = 0; i < threads.length; i++) threads[i].join();
System.out.println("======= 所有任务已完成 =======");
}
}
输出结果
11:14:56:687 : 线程 3 到达, 等待其他线程到齐
11:14:56:687 : 线程 1 到达, 等待其他线程到齐
11:14:59:688 : 线程 5 到达, 等待其他线程到齐
11:15:00:687 : 线程 8 到达, 等待其他线程到齐
11:15:01:688 : 线程 4 到达, 等待其他线程到齐
11:15:03:687 : 线程 2 到达, 等待其他线程到齐
11:15:04:688 : 线程 6 到达, 等待其他线程到齐
11:15:04:688 : 线程 7 到达, 等待其他线程到齐
11:15:04:688 : 线程 9 到达, 等待其他线程到齐
11:15:05:688 : 线程 0 到达, 等待其他线程到齐
11:15:05:688 : 线程 0 开始工作
11:15:05:688 : 线程 1 开始工作
11:15:05:688 : 线程 3 开始工作
11:15:05:688 : 线程 7 开始工作
11:15:05:688 : 线程 6 开始工作
11:15:05:688 : 线程 2 开始工作
11:15:05:688 : 线程 4 开始工作
11:15:05:688 : 线程 8 开始工作
11:15:05:688 : 线程 5 开始工作
11:15:05:688 : 线程 9 开始工作
======= 所有任务已完成 =======
二,作为可重复栅栏使用,等待所有线程到齐再往下
public class TestCyclicBarrier {
private static CyclicBarrier barrier;
private static SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
static class GatherAction implements Runnable {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 到达, 等待其他线程到齐");
barrier.await(); //开始拦截线程,等待所有线程到齐才往下
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 开始工作");
Thread.sleep(new Random().nextInt(10) * 1000);
barrier.await();
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 工作已完成");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
barrier = new CyclicBarrier(10); // 设定计数器计数为 10
Thread[] threads = new Thread[10];// 开启 10 个线程
GatherAction action = new GatherAction(); // 实例化 Runnable 对象
for (int i = 0; i < threads.length; i++) threads[i] = new Thread(action, "线程 " + i);
for (int i = 0; i < threads.length; i++) threads[i].start();
for (int i = 0; i < threads.length; i++) threads[i].join();
System.out.println("======= 所有任务已完成 =======");
}
}
输出结果
11:19:08:808 : 线程 0 到达, 等待其他线程到齐
11:19:08:808 : 线程 5 到达, 等待其他线程到齐
11:19:10:809 : 线程 1 到达, 等待其他线程到齐
11:19:11:808 : 线程 2 到达, 等待其他线程到齐
11:19:11:808 : 线程 9 到达, 等待其他线程到齐
11:19:16:809 : 线程 8 到达, 等待其他线程到齐
11:19:16:809 : 线程 4 到达, 等待其他线程到齐
11:19:16:809 : 线程 6 到达, 等待其他线程到齐
11:19:17:808 : 线程 3 到达, 等待其他线程到齐
11:19:17:808 : 线程 7 到达, 等待其他线程到齐
11:19:17:808 : 线程 7 开始工作
11:19:17:808 : 线程 0 开始工作
11:19:17:808 : 线程 5 开始工作
11:19:17:808 : 线程 9 开始工作
11:19:17:808 : 线程 2 开始工作
11:19:17:808 : 线程 3 开始工作
11:19:17:808 : 线程 1 开始工作
11:19:17:808 : 线程 6 开始工作
11:19:17:808 : 线程 4 开始工作
11:19:17:808 : 线程 8 开始工作
11:19:26:809 : 线程 8 工作已完成
11:19:26:809 : 线程 9 工作已完成
11:19:26:809 : 线程 2 工作已完成
11:19:26:809 : 线程 3 工作已完成
11:19:26:809 : 线程 4 工作已完成
11:19:26:809 : 线程 1 工作已完成
11:19:26:809 : 线程 0 工作已完成
11:19:26:809 : 线程 6 工作已完成
11:19:26:809 : 线程 5 工作已完成
11:19:26:809 : 线程 7 工作已完成
======= 所有任务已完成 =======
三,作为有集合完成相应动作的可重复栅栏使用,等待所有线程到齐再往下
public class TestCyclicBarrier {
private static CyclicBarrier barrier;
private static SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
static class GatherAction implements Runnable {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 到达, 等待其他线程到齐");
barrier.await(); //开始拦截线程,等待所有线程到齐才往下
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 开始工作");
Thread.sleep(new Random().nextInt(10) * 1000);
barrier.await();
System.out.println(formatter.format(new Date()) + " : " + Thread.currentThread().getName() + " 工作已完成");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}
/**
* 用于在线程集队完毕时执行的操作
*/
static class GatherCompleteAction implements Runnable {
@Override
public void run() {
System.out.println(formatter.format(new Date()) + " : " + "======= 所有线程到齐,继续下个步骤 ======= ");
}
}
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
Thread[] threads = new Thread[10];// 开启 10 个线程
GatherAction action = new GatherAction(); // 实例化 Runnable 对象
barrier = new CyclicBarrier(10, new GatherCompleteAction()); // 为集合完成添加动作
for (int i = 0; i < threads.length; i++) threads[i] = new Thread(action, "线程 " + i);
for (int i = 0; i < threads.length; i++) threads[i].start();
for (int i = 0; i < threads.length; i++) threads[i].join();
System.out.println("======= 所有任务已完成 =======");
}
}
输出结果
11:24:56:456 : 线程 1 到达, 等待其他线程到齐
11:24:56:456 : 线程 0 到达, 等待其他线程到齐
11:24:57:456 : 线程 7 到达, 等待其他线程到齐
11:24:58:456 : 线程 9 到达, 等待其他线程到齐
11:25:00:456 : 线程 5 到达, 等待其他线程到齐
11:25:01:456 : 线程 4 到达, 等待其他线程到齐
11:25:01:456 : 线程 6 到达, 等待其他线程到齐
11:25:02:456 : 线程 2 到达, 等待其他线程到齐
11:25:02:456 : 线程 8 到达, 等待其他线程到齐
11:25:04:455 : 线程 3 到达, 等待其他线程到齐
11:25:04:455 : ======= 所有线程到齐,继续下个步骤 =======
11:25:04:456 : 线程 3 开始工作
11:25:04:456 : 线程 1 开始工作
11:25:04:456 : 线程 0 开始工作
11:25:04:456 : 线程 4 开始工作
11:25:04:456 : 线程 5 开始工作
11:25:04:456 : 线程 9 开始工作
11:25:04:456 : 线程 7 开始工作
11:25:04:456 : 线程 8 开始工作
11:25:04:456 : 线程 2 开始工作
11:25:04:456 : 线程 6 开始工作
11:25:12:457 : ======= 所有线程到齐,继续下个步骤 =======
11:25:12:457 : 线程 2 工作已完成
11:25:12:457 : 线程 8 工作已完成
11:25:12:457 : 线程 3 工作已完成
11:25:12:457 : 线程 7 工作已完成
11:25:12:457 : 线程 9 工作已完成
11:25:12:457 : 线程 0 工作已完成
11:25:12:457 : 线程 1 工作已完成
11:25:12:457 : 线程 5 工作已完成
11:25:12:457 : 线程 6 工作已完成
11:25:12:457 : 线程 4 工作已完成
======= 所有任务已完成 =======