Java 多线程高并发 3.7 — CyclicBarrier(循环栅栏)简单使用

如果有了解过 CountDownLatch 的话,这个应该不难理解,相当于 CountDownLatch 的升级版,使得栅栏可重复使用,下面讲讲大概意思和用法

  1. 内部有一个计数器,用于记录剩下还没就绪的线程数量
  2. 内部使用的是 ReentrantLock ,相当于对 ReentrantLock 作了封装
  3. 和 CountDownLatch 的无别在于,CountDownLatch 是一个线程等待其他线程完成,CyclicBarrier 是多个线程互相等待;CountDownLatch 的计数器只能用一次,CyclicBarrier 可以多次使用
  4. 主要的 api 只有 await() 这个方法,调用这个方法时,CyclicBarrier 中的计数器会减少,调用这个方法的线程会被阻塞,直到计数器为 0,所有被阻塞的线程会一起放行
  5. 想要提高并发量的话用这个可以,等于水库积攒水,够了放一波出来
  6. 要注意栅栏计数器 count 的数量和调用 await() 方法的线程数量是否一致,如果 count > await(),永远无法集合完成,会一直阻塞;而 count < await() 并且 await() 不是 count 的整数倍呢?剩下的,哈哈哈哈,想想 ︿( ̄︶ ̄)︿
  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() + " 开始工作");
			} 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 工作已完成
======= 所有任务已完成 =======

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值