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

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; // 设置许可数为 3final 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.pswp.cn/diannao/84358.shtml

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

相关文章

【Java多线程】多线程状态下如何安全使用ArrayList以及哈希表

&#x1f50d; 开发者资源导航 &#x1f50d;&#x1f3f7;️ 博客主页&#xff1a; 个人主页&#x1f4da; 专栏订阅&#xff1a; JavaEE全栈专栏 多线程安全使用ArrayList 手动加锁 日常中最常用的方法&#xff0c;使用synchronized进行加锁&#xff0c;把代码打包成一份&a…

InnoDB引擎底层解析(二)之InnoDB的Buffer Pool(三)

Buffer Pool 实例 我们上边说过&#xff0c;Buffer Pool 本质是 InnoDB 向操作系统申请的一块连续的内存空间&#xff0c;在多线程环境下&#xff0c;访问 Buffer Pool 中的各种链表都需要加锁处理&#xff0c;在Buffer Pool特别大而且多线程并发访问特别高的情况下&#xff0…

Netty学习专栏(三):Netty重要组件详解(Future、ByteBuf、Bootstrap)

文章目录 前言一、Future & Promise&#xff1a;异步编程的救星1.1 传统NIO的问题1.2 Netty的解决方案1.3 代码示例&#xff1a;链式异步操作 二、ByteBuf&#xff1a;重新定义数据缓冲区2.1 传统NIO ByteBuffer的缺陷2.2 Netty ByteBuf的解决方案2.3 代码示例&#xff1a;…

Vue3逐步抛弃虚拟Dom,React如何抉择

虚拟DOM&#xff1a;前端界的替死鬼 这玩意儿就是个前端开发的充气娃娃&#xff01; 你以为它很牛逼&#xff1f;无非是给真DOM当替死鬼&#xff01; 每次数据变&#xff0c;虚拟DOM先搁内存里自嗨一顿&#xff0c;diff算法跟便秘似的算半天&#xff0c;最后才敢碰真DOM。 说白…

分布式锁总结

文章目录 分布式锁什么是分布式锁&#xff1f;分布式锁的实现方式基于数据库(mysql)实现基于缓存(redis)多实例并发访问问题演示项目代码(使用redis)配置nginx.confjmeter压测复现问题并发是1&#xff0c;即不产生并发问题并发30测试,产生并发问题(虽然单实例是synchronized&am…

解决自签名证书HTTPS告警:强制使用SHA-256算法生成证书

解决自签名证书HTTPS告警&#xff1a;强制使用SHA-256算法生成证书 一、问题场景 在使用OpenSSL生成和配置自签名证书时&#xff0c;常遇到以下现象&#xff1a; 浏览器已正确导入根证书&#xff08;.pem文件&#xff09;&#xff0c;但访问HTTPS站点时仍提示不安全连接或证…

线上 Linux 环境 MySQL 磁盘 IO 高负载深度排查与性能优化实战

目录 一、线上告警 二、问题诊断 1. 系统层面排查 2. 数据库层面分析 三、参数调优 1. sync_binlog 参数优化 2. innodb_flush_log_at_trx_commit 参数调整 四、其他优化建议 1. 日志文件位置调整 2. 生产环境核心参数配置模板 3. 突发 IO 高负载应急响应方案 五、…

window 显示驱动开发-初始化和 DMA 缓冲区创建

若要指示 GPU 支持 GDI 硬件加速&#xff0c;显示微型端口驱动程序的 DriverEntry 函数实现必须使用指向驱动程序实现的 DxgkDdiRenderKm 函数的指针填充 DRIVER_INITIALIZATION_DATA 结构的 DxgkDdiRenderKm 成员。 DirectX 图形内核子系统调用 DxgkDdiRenderKm 函数&#xf…

Go语言实战:使用 excelize 实现多层复杂Excel表头导出教程

Go 实现支持多层复杂表头的 Excel 导出工具 目录 项目介绍依赖说明核心结构设计如何支持多层表头完整使用示例总结与扩展 项目介绍 在实际业务系统中&#xff0c;Excel 文件导出是一项常见功能&#xff0c;尤其是报表类需求中常见的复杂多级表头&#xff0c;常规表格组件往…

机器视觉6-halcon高级教程

机器视觉6-halcon高级教程 双目立体视觉原理视差外极线几何双目标定 双目立体视觉之Halcon标定一&#xff0e;标定结果二.Halcon标定过程1.获取左右相机图像中标定板的区域;2.提取左右相机图像中标定板的MARK点坐标和摄像机外部参数;3.执行双目标定;4.获取非标准外极线几何到标…

板凳-------Mysql cookbook学习 (六)

2025年Pytorch-gpu版本安装&#xff08;各种情况适用自己的安装需求&#xff0c;亲测绝对有效&#xff0c;示例安装torch2.6.0&#xff0c;过程详细面向小白&#xff09;_torch gpu版本-CSDN博客 https://blog.csdn.net/OpenSeek/article/details/145795127 2.2 查错 import s…

Spring boot和SSM项目对比

目录对比 springboot目录 project├─src│ ├─main│ │ ├─java│ │ │ ├─com.example.demo│ │ │ │ ├─config // 存放SpringBoot的配置类│ │ │ │ ├─controller // 存放控制器类│ │ │ │ ├─entity // 存…

《关于浔川社团退出DevPress社区及内容撤回的声明》

《关于浔川社团退出DevPress社区及内容撤回的声明》 尊敬的DevPress社区及读者&#xff1a; 经浔川社团内部决议&#xff0c;我社决定自**2025年5月26日**起正式退出DevPress社区&#xff0c;并撤回所有由我社成员在该平台发布的原创文章。相关事项声明如下&#xff1a; …

Python性能优化利器:__slots__的深度解析与避坑指南

核心场景&#xff1a;当需要创建数百万个属性固定的对象时&#xff0c;默认的__dict__字典存储会造成巨大内存浪费。此时__slots__能通过元组结构取代字典&#xff0c;显著提升内存效率&#xff08;实测节省58%内存&#xff09;&#xff01; 底层原理&#xff1a;为何能节省内…

Go 语言中的 Struct Tag 的用法详解

在 Go 语言中&#xff0c;结构体字段标签&#xff08;Struct Tag&#xff09; 是一种用于给字段添加元信息&#xff08;metadata&#xff09;的机制&#xff0c;常用于序列化&#xff08;如 JSON、XML&#xff09;、ORM 映射、验证等场景。你在开发 Web 应用或处理数据交互时&a…

微软正式发布 SQL Server 2025 公开预览版,深度集成AI功能

微软在今年的 Build 2025 大会上正式发布了 SQL Server 2025 公开预览版&#xff0c;标志着这一经典数据库产品在 AI 集成、安全性、性能及开发者工具方面的全面升级。 AI 深度集成与创新 原生向量搜索&#xff1a;SQL Server 2025 首次将 AI 功能直接嵌入数据库引擎&#xff…

React从基础入门到高级实战:React 基础入门 - React 的工作原理:虚拟 DOM 与 Diff 算法

React 的工作原理&#xff1a;虚拟 DOM 与 Diff 算法 引言 React 是现代前端开发的明星框架&#xff0c;它的出现彻底改变了我们构建用户界面的方式。无论是动态的 Web 应用还是复杂的单页应用&#xff08;SPA&#xff09;&#xff0c;React 都能以高效的渲染机制和简洁的组件…

解释一下NGINX的反向代理和正向代理的区别?

大家好&#xff0c;我是锋哥。今天分享关于【解释一下NGINX的反向代理和正向代理的区别?】面试题。希望对大家有帮助&#xff1b; 解释一下NGINX的反向代理和正向代理的区别? NGINX的反向代理和正向代理的区别主要体现在它们的功能和使用场景上。下面我会详细解释它们的定义…

Python学习——执行python时,键盘按下ctrl+c,退出程序

在 Python 中&#xff0c;当用户按下 CtrlC 时&#xff0c;程序默认会触发 KeyboardInterrupt 异常并终止。 1. 捕获 KeyboardInterrupt 异常&#xff08;推荐&#xff09; 使用 try-except 块直接捕获 KeyboardInterrupt 异常&#xff0c;适用于简单场景。 示例代码&#xff…

C++ 反向迭代器(Reverse Iterator)实现详解

目录 1. 反向迭代器概述 2. 代码实现分析 3. 关键点解析 3.1 模板参数设计 3.2 核心操作实现 4. 使用示例 1. 反向迭代器概述 反向迭代器是STL中一种重要的适配器&#xff0c;它允许我们以相反的顺序遍历容器。本文将详细讲解如何实现一个自定义的反向迭代器模板类。 2.…