CyclicBarrier:Java并发编程中的循环屏障原理解析

CyclicBarrier:Java并发编程中的循环屏障

在Java并发编程中,CyclicBarrier是一种非常有用的工具,允许多个线程相互等待,直到所有参与的线程都达到一个特定的屏障点。这种同步机制在很多场景中非常有用,比如并行任务分发、数据收集、会议厅模型等。在本文中,我们将深入探讨CyclicBarrier的实现和工作原理,并通过一个简单的Java代码示例来展示其用法。

一、CyclicBarrier的实现

1. 基本结构

CyclicBarrier的内部结构主要由一个同步队列和一个屏障点组成。当线程达到屏障点时,它会被添加到一个内部队列中,并且会阻塞,直到所有参与的线程都达到屏障点。一旦所有线程都到达屏障点,它们将同时被唤醒并继续执行。

java 复制代码
public class CyclicBarrier {
    private final int parties;
    private final int barrier;
    private final CyclicBarrierQueue barrierQueue;
    private int waiting;

    public CyclicBarrier(int parties) {
        this.parties = parties;
        this.barrier = parties;
        this.barrierQueue = new CyclicBarrierQueue(this);
        this.waiting = 0;
    }
    ...
}

2. 同步队列

CyclicBarrier内部使用了一个基于数组的队列实现,称为CyclicBarrierQueue。该队列用于存储达到屏障点的线程,并确保线程在等待时被正确地唤醒。

3. 屏障点

屏障点是CyclicBarrier的一个重要成员变量,它用于标记屏障的位置。当线程达到屏障点时,它会将自己的引用来替换这个屏障点。

4. 等待和唤醒

CyclicBarrier通过wait和notify方法来实现线程的等待和唤醒。当线程达到屏障点时,它会将自己加入到队列中并调用wait方法进入等待状态。当所有线程都达到屏障点时,CyclicBarrier会调用notify方法来唤醒所有等待的线程。

二、CyclicBarrier的工作原理分析

1. 设定屏障点

在CyclicBarrier中,屏障点是固定的,与参与的线程数相等。每个线程在达到屏障点时会将自己的引用添加到队列中,并阻塞等待直到所有线程都达到屏障点。

2. 等待和唤醒

当一个线程达到屏障点时,它将调用wait方法进入等待状态。此时线程将被添加到队列中并阻塞等待。当所有线程都达到屏障点时,CyclicBarrier会调用notify方法来唤醒所有等待的线程。这些被唤醒的线程将继续执行后续的逻辑。

3. 循环使用

由于CyclicBarrier内部使用了一个基于数组的队列实现,因此在达到屏障点的线程数量达到一定阈值后,队列将循环使用数组中的空间。这样可以有效地利用内存空间并支持大规模的并发线程等待。

三、简单Java代码示例

下面是一个使用CyclicBarrier的简单Java代码示例。在这个示例中,我们创建了10个线程,这些线程将同时到达屏障点并等待,直到所有线程都到达屏障点才会继续执行。

java 复制代码
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        final int parties = 10;  // 参与线程数
        CyclicBarrier barrier = new CyclicBarrier(parties);  // 创建屏障对象

        for (int i = 0; i < parties; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " reached the barrier.");
                try {
                    barrier.await();  // 当前线程到达屏障点并等待
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " continues to run.");
            }).start();  // 启动线程
        }
    }
}

在这个示例中,我们首先定义了参与线程数(parties)为10。然后创建了一个CyclicBarrier对象,并将参与线程数作为参数传递给它。接下来,我们使用一个for循环创建了10个线程,每个线程都会在达到屏障点时调用barrier.await()方法进入等待状态。最后,当所有线程都达到屏障点时,它们将同时被唤醒并继续执行后续的逻辑。

相关推荐
雨中飘荡的记忆38 分钟前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
over6973 小时前
从 LLM 到全栈 Agent:MCP 协议 × RAG 技术如何重构 AI 的“做事能力”
面试·llm·mcp
心之语歌3 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
SuperEugene4 小时前
Vue状态管理扫盲篇:如何设计一个合理的全局状态树 | 用户、权限、字典、布局配置
前端·vue.js·面试
华仔啊4 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang4 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang6 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Sailing6 小时前
🚀 别再乱写 16px 了!CSS 单位体系已经进入“计算时代”,真正的响应式布局
前端·css·面试
Java水解6 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SuperEugene9 小时前
Vue状态管理扫盲篇:Vuex 到 Pinia | 为什么大家都在迁移?核心用法对比
前端·vue.js·面试