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
繁體地址,請注明出處:http://hk.pswp.cn/diannao/84358.shtml
英文地址,請注明出處:http://en.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.…