初学CyclicBarrier回环栅栏

本文通过实例详细解析了CyclicBarrier的使用方法及应用场景,演示了如何利用CyclicBarrier实现多线程间的同步等待。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我不喜欢讲理论, 直接上代码看效果, 简单''粗暴''!

代码1:

	public static void main(String[] args) throws Exception {
		
		CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
		
		for (int i = 0; i < 3; i++) {
			System.out.println("第"+i+"次循环开始");
			cyclicBarrier.await();
			System.out.println("第"+i+"次循环结束");
		}
	}

首先创建CyclicBarrier对象, 构造传入一个int类型, 这里传入3 , 表示需要有3个线程调用 cyclicBarrier对象的await()方法后,

所有的线程到cyclicBarrier.await()代码后的代码才会继续执行

所以这段代码结果如下:


代码2:

    public static void main(String[] args) throws Exception {

		CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
		
		new Thread() {
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+":执行你想要的操作");
					Thread.sleep(5000);
					cyclicBarrier.await();//让当前线程到await状态
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+":执行后续操作");
			}
		}.start();
		
		new Thread() {
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+":执行你想要的操作");
					Thread.sleep(7000);
					cyclicBarrier.await();//让当前线程到await状态
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+":执行后续操作");
			}
		}.start();

		for (int i = 0; i < 3; i++) {
			System.out.println("第" + i + "次循环开始");
			cyclicBarrier.await();//让当前线程到await状态
			System.out.println("第" + i + "次循环结束");
		}
    }

创建了2个线程, 并且让每个线程都到await状态, (为了看到效果,可以让线程睡眠一下),结果:

可以看到, 当有3个线程调用了 cyclicBarrier.await(), 后第1次循环就执行完,  

但是第2次循环, 又停住了,   因为CyclicBarrier 对象是循环使用的,  即: 回环

所以又要有3个线程执行: cyclicBarrier.await();  则第2次循环才回执行完


我们抽取创建线程的代码,

代码3:

	public static void main(String[] args) throws Exception {

		CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

		for (int i = 0; i < 3; i++) {
			System.out.println("第" + i + "次循环开始");

			if (i == 0 || i == 1) {
				// 创建2个线程, 执行cyclicBarrier.await();
				createTwoThreadExcuteAwait(cyclicBarrier);
			}

			cyclicBarrier.await();// 让当前线程到await状态
			System.out.println("第" + i + "次循环结束");
		}

	}

	private static void createTwoThreadExcuteAwait(CyclicBarrier cyclicBarrier) {
		new Thread() {
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName() + ":执行你想要的操作");
					Thread.sleep(5000);
					cyclicBarrier.await();// 让当前线程到await状态
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + ":执行后续操作");
			}
		}.start();

		new Thread() {
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName() + ":执行你想要的操作");
					Thread.sleep(7000);
					cyclicBarrier.await();// 让当前线程到await状态
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + ":执行后续操作");
			}
		}.start();

	}

结果如下, 你应该也可猜到: 第3次循环只开始,没有结束(这里打印的是i的值, i从0开始,所以为"第2次循环") 

到现在, 应该明白这个CyclicBarrier,这个回环栅栏的简单使用吧


应用场景:(个人想法)

比如用户上传大文件, 后台将一个大文件分成很多小文件, 多线程往很多数据库存数据,   当所有数据库都写完了, 

才能往主数据库记录文件信息和上传状态等

,然后才能返回给用户,上传成功!

等等!

<think>我们正在讨论CyclicBarrier,根据引用内容,CyclicBarrierJava并发库中的一个同步工具,用于让一组线程等待至某个屏障点(barrier)再同时执行,并且可以重用。 概念:CyclicBarrier字面意思是可循环使用(Cyclic)的屏障(Barrier)。它允许一组线程相互等待,直到所有线程都到达屏障点,然后屏障打开,所有线程继续执行。因为可以重用,所以称为循环屏障。 原理:通过引用[1][3]可知,CyclicBarrier内部使用ReentrantLock(独占锁)和Condition来实现线程的阻塞和唤醒。它维护一个计数器,当线程调用await()方法时,计数器减1,然后线程被阻塞(通过Condition.await())。当计数器减到0时,表示所有线程都已到达屏障点,此时通过Condition.signalAll()唤醒所有被阻塞的线程,同时重置计数器(以便重用)或者执行预定义的屏障动作(如果提供了Runnable任务)。 应用场景: 1. 多线程计算数据,最后合并计算结果的场景。 2. 模拟高并发,用于压力测试,模拟一定数量的并发用户同时执行操作。 3. 游戏服务器中,多个玩家都准备好后才开始游戏。 下面我们详细展开:</think>### CyclicBarrier 循环屏障(回环栅栏)详解 #### 一、核心概念 CyclicBarrierJava 并发包 (`java.util.concurrent`) 中的同步工具,其核心设计可概括为: 1. **循环屏障** - 让一组线程在**屏障点(Barrier Point)** 相互等待 - 当所有线程到达屏障时,屏障才会打开,所有线程**同时继续执行** - 如登山队在山脚集合点等待全员到齐后同时出发 2. **可重用性**(核心特性) 屏障释放线程后可**自动重置**,支持重复使用(区别于一次性 CountDownLatch)[^1][^3][^5] ```java CyclicBarrier barrier = new CyclicBarrier(3); // 创建3线程屏障 // 第一次使用:3线程到达屏障后继续执行 // 重置后第二次使用:再次等待3线程到达屏障 ``` 3. **屏障动作** 支持在所有线程通过屏障后执行自定义任务(由最后到达屏障的线程执行)[^2] ```java Runnable barrierAction = () -> System.out.println("全员已就绪!"); CyclicBarrier barrier = new CyclicBarrier(3, barrierAction); ``` #### 二、实现原理(基于源码分析) 通过 **ReentrantLock + Condition** 实现线程协调[^1]: ```mermaid graph LR A[线程1调用await] --> B[获取ReentrantLock锁] B --> C{计数count-1} C -->|count>0| D[condition.await阻塞] C -->|count=0| E[执行屏障动作] E --> F[condition.signalAll唤醒所有线程] F --> G[重置count] ``` 1. **关键成员变量** ```java private final ReentrantLock lock = new ReentrantLock(); private final Condition trip = lock.newCondition(); private int count; // 剩余等待线程数 private final int parties; // 屏障需要的总线程数 private final Runnable barrierCommand; // 屏障动作 ``` 2. **await() 工作流程** ```java public int await() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lock(); try { int index = --count; // 计数减1 if (index == 0) { // 最后一个线程到达 if (barrierCommand != null) barrierCommand.run(); trip.signalAll(); // 唤醒所有线程 reset(); // 重置计数器(count=parties) return 0; } while (index > 0) { // 非最后线程 trip.await(); // 阻塞等待 } return index; } finally { lock.unlock(); } } ``` #### 三、典型应用场景 1. **多阶段计算任务** 分布式计算中合并子任务结果: ```java // 模拟3个线程分别计算数据 CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("所有子任务完成,开始合并结果"); }); IntStream.range(0,3).forEach(i -> new Thread(() -> { calculateData(i); // 执行计算 barrier.await(); // 等待其他线程 mergeResults(); // 合并结果 }).start()); ``` 2. **压力测试框架** 模拟高并发场景: ```java CyclicBarrier startBarrier = new CyclicBarrier(1000); // 1000并发 ExecutorService pool = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { pool.execute(() -> { startBarrier.await(); // 等待1000个线程就绪 simulateUserRequest(); // 同时发起请求 }); } ``` 3. **游戏服务器同步** 多玩家回合制游戏: ```java CyclicBarrier roundBarrier = new CyclicBarrier(4, () -> { System.out.println("--- 新回合开始 ---"); }); // 4个玩家线程 players.forEach(player -> new Thread(() -> { while (!gameOver) { playerAction(); // 玩家操作 roundBarrier.await(); // 等待其他玩家 } }).start()); ``` #### 四、与 CountDownLatch 对比 | **特性** | CyclicBarrier | CountDownLatch | |------------------------|--------------------------------|-------------------------| | 重置能力 | ✅ 自动重置(可重用)[^3] | ❌ 一次性 | | 计数方向 | 递减(parties→0) | 递减(设定值→0) | | 阻塞线程 | 所有线程相互等待 | 调用线程等待其他线程 | | 屏障动作 | ✅ 支持自定义任务 | ❌ 不支持 | | 典型场景 | 多阶段并行任务 | 主线程等待子任务初始化 | > ⚠️ **注意**:线程被中断或超时会导致 `BrokenBarrierException`,此时屏障将进入破损状态,需调用 `reset()` 重置[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值