Java 并发编程高级技巧:CyclicBarrier、CountDownLatch 和 Semaphore 的高级应用

news2025/5/25 13:49:18

Java 并发编程高级技巧:CyclicBarrier、CountDownLatch 和 Semaphore 的高级应用

一、引言

在 Java 并发编程中,CyclicBarrier、CountDownLatch 和 Semaphore 是三个常用且强大的并发工具类。它们在多线程场景下能够帮助我们实现复杂的线程协调与资源控制。本文将深入探讨这三个类的高级应用,旨在帮助读者更好地理解和运用这些并发工具来解决实际工作中遇到的多线程问题。

二、CyclicBarrier 的高级应用

(一)多阶段任务的协调

CyclicBarrier 可以用于多阶段任务的场景,例如在一个复杂的计算任务中,需要将任务分为多个阶段,多个线程分别处理不同阶段的数据,只有当所有线程都完成当前阶段的任务后,才能进入下一个阶段。

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numThreads = 3; // 线程数
        CyclicBarrier barrier = new CyclicBarrier(numThreads, () -> {
            System.out.println("所有线程都完成当前阶段,进入下一阶段");
        });

        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                for (int stage = 1; stage <= 3; stage++) { // 3 个阶段的任务
                    System.out.println(Thread.currentThread().getName() + " 开始处理阶段 " + stage);
                    try {
                        Thread.sleep((long) (Math.random() * 1000)); // 模拟任务处理时间
                        System.out.println(Thread.currentThread().getName() + " 完成处理阶段 " + stage);
                        barrier.await(); // 等待所有线程完成当前阶段
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

在这个例子中,我们创建了 3 个线程来处理 3 个阶段的任务。每个阶段的末尾,线程都会调用 barrier.await() 方法等待其他线程完成当前阶段的任务。当所有线程都到达屏障点后,屏障的阻塞状态被重置,所有线程可以继续进入下一个阶段。通过这种方式,我们实现了多阶段任务的协调处理。

(二)性能优化与源码解析

CyclicBarrier 内部是通过循环Barrier机制来实现的。其核心是通过一个计数器来记录到达屏障点的线程数。当计数器达到指定的线程数时,释放所有等待的线程,并重置计数器。这种机制使得 CyclicBarrier 可以循环使用,即在多个任务阶段中重复使用同一个屏障。

在性能优化方面,我们需要注意 CyclicBarrier 的屏障数(构造函数中的参数)的选择。过大的屏障数可能导致线程等待时间过长,影响程序的响应速度;而过小的屏障数可能无法满足任务协调的需求。在实际应用中,需要根据任务的特性和线程的工作负载来合理设置屏障数。

三、CountDownLatch 的高级应用

(一)资源初始化与任务启动控制

CountDownLatch 可以用于控制资源的初始化和任务的启动。例如,在多线程应用程序中,我们需要确保某些资源(如配置文件、数据库连接池等)在所有工作线程开始执行任务之前已经初始化完成。我们可以通过设置一个初始计数的 CountDownLatch,多个线程在开始任务前都先调用 await() 方法等待计数器变为 0,而负责初始化资源的线程在完成初始化后调用 countDown() 方法减少计数器的值。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) {
        final int numThreads = 5;
        CountDownLatch latch = new CountDownLatch(1); // 初始计数为 1

        // 工作线程
        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 等待资源初始化完成");
                    latch.await(); // 等待资源初始化完成
                    System.out.println(Thread.currentThread().getName() + " 资源初始化完成,开始执行任务");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        // 模拟资源初始化过程
        new Thread(() -> {
            System.out.println("开始初始化资源");
            try {
                Thread.sleep(2000); // 模拟资源初始化所需时间
                System.out.println("资源初始化完成");
                latch.countDown(); // 初始化完成,减少计数器
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

在这个例子中,5 个工作线程都先等待 CountDownLatch 的计数器变为 0。负责初始化资源的线程在完成初始化后调用 countDown() 方法,使得工作线程可以从 await() 方法中唤醒,开始执行任务。这种机制确保了资源的正确初始化和任务的有序启动。

(二)性能测试与源码机制

CountDownLatch 的实现是通过一个内部的同步器(AQS)来管理计数器的。当计数器为 0 时,同步器会释放所有等待的线程。CountDownLatch 的计数器只能减少,不能增加,这使得它适用于一次性事件等待的场景。

在性能测试方面,CountDownLatch 可以用于控制多个线程同时开始执行任务,从而测量任务的执行时间和性能。例如,在测试某个计算密集型任务的性能时,我们可以使用多个线程同时执行任务,并通过 CountDownLatch 来控制这些线程同时开始执行,然后记录任务的完成时间。

四、Semaphore 的高级应用

(一)资源访问控制与流量控制

Semaphore 可以用于控制对资源的访问和流量控制。例如,在一个高并发的 Web 应用中,为了防止服务器过载,我们可以使用 Semaphore 来限制同时处理的请求数量。当请求数量超过设定的许可数时,后续的请求将被阻塞,直到有许可可用。

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        final int numThreads = 10;
        final int permits = 3; // 设置许可数为 3
        final Semaphore semaphore = new Semaphore(permits);

        // 多个请求线程
        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 正在等待获取许可");
                    semaphore.acquire(); // 获取许可
                    System.out.println(Thread.currentThread().getName() + " 获取许可,开始处理请求");

                    Thread.sleep((long) (Math.random() * 2000)); // 模拟处理请求时间

                    System.out.println(Thread.currentThread().getName() + " 处理请求完成,释放许可");
                    semaphore.release(); // 释放许可
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

在这个例子中,我们设置了 3 个许可。当有多个请求线程同时尝试获取许可时,只有 3 个线程可以同时获得许可并处理请求。其他线程将被阻塞,等待许可释放。这种机制可以有效地控制资源的访问和流量,防止系统过载。

(二)公平性与性能优化

Semaphore 有公平和非公平两种模式。公平模式下,线程按照请求的顺序获取许可;非公平模式下,线程可能随机获取许可。非公平模式通常具有更高的吞吐量,因为它允许更多的线程尝试获取许可。在实际应用中,我们需要根据具体的场景和需求来选择公平或非公平模式。

在性能优化方面,我们需要注意 Semaphore 的许可数设置。过小的许可数可能导致系统资源未充分利用,请求处理速度过慢;过大的许可数可能导致系统过载。我们需要根据系统的实际负载能力和服务请求的特点来合理设置许可数,以达到最佳的性能平衡。

五、总结

CyclicBarrier、CountDownLatch 和 Semaphore 是 Java 并发编程中不可或缺的工具类。通过本文的介绍,我们深入探讨了它们的高级应用,包括多阶段任务协调、资源初始化与任务启动控制、资源访问控制与流量控制等场景。同时,我们也对它们的源码机制和性能优化策略进行了分析。在实际开发中,灵活运用这些并发工具类,可以大大提高我们处理复杂多线程问题的能力,构建高效、可靠的并发应用程序。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PT5F2307触摸A/D型8-Bit MCU

1. 产品概述 ● PT5F2307是一款51内核的触控A/D型8位MCU&#xff0c;内置16K*8bit FLASH、内部256*8bit SRAM、外部512*8bit SRAM、触控检测、12位高精度ADC、RTC、PWM等功能&#xff0c;抗干扰能力强&#xff0c;适用于滑条遥控器、智能门锁、消费类电子产品等电子应用领域。 …

线性代数中的向量与矩阵:AI大模型的数学基石

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

打卡第27天:函数的定义与参数

知识点回顾&#xff1a; 1.函数的定义 2.变量作用域&#xff1a;局部变量和全局变量 3.函数的参数类型&#xff1a;位置参数、默认参数、不定参数 4.传递参数的手段&#xff1a;关键词参数 5.传递参数的顺序&#xff1a;同时出现三种参数类型时 作业&#xff1a; 题目1&a…

python训练营day34

知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数GPU性能的查看&#xff1a;看显存、看级别、看架构代际GPU训练的方法&#xff1a;数据和模型移动到GPU device上类的call方法&#xff1a;为什么定义前向传播时可以直接写作self.fc1(x) 作业 复习今…

人工智能在医疗影像诊断上的最新成果:更精准地识别疾病

摘要&#xff1a;本论文深入探讨人工智能在医疗影像诊断领域的最新突破&#xff0c;聚焦于其在精准识别疾病方面的显著成果。通过分析深度学习、多模态影像融合、三维重建与可视化以及智能辅助诊断系统等关键技术的应用&#xff0c;阐述人工智能如何提高医疗影像诊断的准确性和…

塔能节能平板灯:点亮苏州某零售工厂节能之路

在苏州某零售工厂的运营成本中&#xff0c;照明能耗占据着一定比例。为降低成本、提升能源利用效率&#xff0c;该工厂与塔能科技携手&#xff0c;引入塔能节能平板灯&#xff0c;开启了精准节能之旅&#xff0c;并取得了令人瞩目的成效。 一、工厂照明能耗困境 苏州该零售工厂…

3DMAX插件UV工具UV Tools命令参数详解

常规: 打开UV工具设置对话框。 右键点击: 隐藏/显示主界面。 添加 为选定对象添加展开修改器。 将从下拉菜单中选择映射通道。 Ctrl+点击: 克隆任何当前的修饰符。 右键点击: 找到第一个未展开的修改器。 地图频道 设置展开映射通道。 Ctrl+Click:添加选定的映射通道的展开…

Docker 与微服务架构:从单体应用到容器化微服务的迁移实践

随着软件系统规模和复杂性的日益增长,传统的单体应用(Monolithic Application)在开发效率、部署灵活性和可伸缩性方面逐渐暴露出局限性。微服务架构(Microservice Architecture)作为一种将大型应用拆分为一系列小型、独立、松耦合服务的模式,正成为现代企业构建弹性、敏捷…

《岁月深处的童真》

在那片广袤而质朴的黄土地上&#xff0c;时光仿佛放慢了脚步&#xff0c;悠悠地流淌着。画面的中央&#xff0c;是一个扎着双髻的小女孩&#xff0c;她静静地伫立着&#xff0c;宛如一朵绽放在岁月缝隙中的小花。 小女孩身着一件略显陈旧的中式上衣&#xff0c;布料的纹理间似乎…

文件夹图像批处理教程

前言 因为经常对图像要做数据清洗&#xff0c;又很费时间去重新写一个&#xff0c;我一直在想能不能写一个通用的脚本或者制作一个可视化的界面对文件夹图像做批量的修改图像大小、重命名、划分数据训练和验证集等等。这里我先介绍一下我因为写过的一些脚本&#xff0c;然后我…

RL电路的响应

学完RC电路的响应&#xff0c;又过了一段时间了&#xff0c;想必很多人都忘了RC电路响应的一些内容。我们这次学习RL电路的响应&#xff0c;以此同时&#xff0c;其实也是带大家一起回忆一些之前所学的RC电路的响应的一些知识点。所以&#xff0c;这次的学习&#xff0c;其实也…

30-消息队列

一、消息队列概述 队列又称消息队列&#xff0c;是一种常用于任务间通信的数据结构&#xff0c;队列可以在任务与任务间、 中断和任务间传递信息&#xff0c;实现了任务接收来自其他任务或中断的不固定长度的消息&#xff0c;任务能够从队列里面读取消息&#xff0c;当队列中的…

Thinkphp6使用token+Validate验证防止表单重复提交

htm页面加 <input type"hidden" name"__token__" value"{:token()}" /> Validate 官方文档 ThinkPHP官方手册

AppAgentx 开源AI手机操控使用分享

项目地址: https://appagentx.github.io/?utm_sourceai-bot.cn GitHub仓库: https://github.com/Westlake-AGI-Lab/AppAgentX/tree/main arXiv技术论文:https://arxiv.org/pdf/2503.02268 AppAgentx是什么: AppAgentX 是西湖大学推出的一种自我进化式 GUI 代理框架。它通过…

Axure设计之带分页的穿梭框原型

穿梭框&#xff08;Transfer&#xff09;是一种常见且实用的交互组件&#xff0c;广泛应用于需要批量选择或分配数据的场景。 一、应用场景 其典型应用场景包括&#xff1a; 权限管理系统&#xff1a;批量分配用户角色或系统权限数据筛选工具&#xff1a;在大数据集中选择特…

电机控制储备知识学习(五) 三项直流无刷电机(BLDC)学习(四)

目录 电机控制储备知识学习&#xff08;五&#xff09;一、三项直流无刷电机(BLDC)学习&#xff08;四&#xff09;1&#xff09;软件方法控制电机转速2&#xff09;PWM概念和PWM的产生3&#xff09;转子位置检测和霍尔传感器的工作原理分析4&#xff09;霍尔传感器安装角度和电…

Java—— 网络爬虫

案例要求 https://hanyu.baidu.com/shici/detail?pid0b2f26d4c0ddb3ee693fdb1137ee1b0d&fromkg0 http://www.haoming8.cn/baobao/10881.html http://www.haoming8.cn/baobao/7641.html上面三个网址分别表示百家姓&#xff0c;男生名字&#xff0c;女生名字&#xff0c;如…

Baklib内容中台的主要构成是什么?

Baklib内容中台核心架构 Baklib作为一站式知识管理平台的核心载体&#xff0c;其架构设计围绕智能搜索引擎优化技术与多终端适配响应系统展开。通过模块化内容组件的灵活配置&#xff0c;企业可快速搭建知识库、FAQ页面及帮助中心等标准化场景&#xff0c;同时借助可视化数据看…

深度解析 Java 中介者模式:重构复杂交互场景的优雅方案

一、中介者模式的核心思想与设计哲学 在软件开发的历史长河中&#xff0c;对象间的交互管理一直是架构设计的核心难题。当多个对象形成复杂的网状交互时&#xff0c;系统会陷入 "牵一发而动全身" 的困境。中介者模式&#xff08;Mediator Pattern&#xff09;作为行…

untiy实现汽车漫游

实现效果 汽车漫游 1.创建汽车模型 导入汽车模型(FBX格式或其他3D格式),确保模型包含车轮、车身等部件。 为汽车添加碰撞体(如 Box Collider 或 Mesh Collider),避免穿透场景物体。 添加 Rigidbody 组件,启用重力并调整质量(Mass)以模拟物理效果。 2.编写汽车控制脚本…