Java JUC并發(fā)集合詳解之線程安全容器完全攻略
在多線程環(huán)境下,直接使用傳統(tǒng)的集合類(如ArrayList, HashMap) 是危險的,會導(dǎo)致數(shù)據(jù)不一致、臟讀等問題。Java通過 java.util.concurrent(JUC)包提供了一整套線程安全的并發(fā)容器,它們不僅是簡單的同步包裝,更是基于精妙并發(fā)算法構(gòu)建的高性能工具。理解并正確使用它們,是開發(fā)穩(wěn)健、高效并發(fā)應(yīng)用的必備技能。
一、為什么需要JUC并發(fā)集合?
傳統(tǒng)的同步方式(如使用 Collections.synchronizedList())是通過在方法上添加synchronized關(guān)鍵字來實現(xiàn)的,這是一種粗粒度的鎖策略,雖然能保證線程安全,但性能堪憂。因為它一次只允許一個線程訪問集合,嚴(yán)重限制了并發(fā)性。
JUC并發(fā)容器的設(shè)計目標(biāo)是在保證線程安全的前提下,最大限度地提升并發(fā)性能。其核心實現(xiàn)理念是:
- 鎖分離:將鎖的粒度細(xì)化,允許多個線程以非沖突的方式同時訪問集合的不同部分。
- 無鎖算法:使用CAS(Compare-And-Swap)等樂觀鎖操作,避免互斥鎖的開銷。
- 寫時復(fù)制:適用于讀多寫少的場景,修改操作時復(fù)制整個容器,從而讓讀操作完全無鎖。
二、核心并發(fā)集合分類與詳解
JUC并發(fā)容器可分為以下幾大類,每一類都針對特定場景進(jìn)行了優(yōu)化。
1. 并發(fā)Map:應(yīng)對高頻鍵值存儲
ConcurrentHashMap(CHM) - 絕對的主角- 替代者:用于替代同步的
HashMap或Hashtable。 - 實現(xiàn)原理:在JDK 8之前,采用分段鎖(Segment),將數(shù)據(jù)分成一段一段存儲,每段配一把鎖,大大提升了并發(fā)度。在JDK 8及之后,進(jìn)行了革命性優(yōu)化:
- 替代者:用于替代同步的
synchronized+ CAS:鎖的粒度從Segment細(xì)化到每個數(shù)組桶位的頭節(jié)點,并發(fā)度更高。- 紅黑樹優(yōu)化:當(dāng)鏈表長度超過8且數(shù)組容量≥64時,鏈表會轉(zhuǎn)為紅黑樹,防止極端情況下哈希沖突導(dǎo)致性能退化。
- 特點:線程安全、高并發(fā)、高性能。是JUC中使用最頻繁的類之一。
ConcurrentSkipListMap- 特點:基于跳表實現(xiàn)的有序并發(fā)Map。
- 適用場景:當(dāng)需要線程安全且要求Map的鍵有序時使用。其并發(fā)性能優(yōu)于同步的
TreeMap。

2. 并發(fā)Queue:高效的任務(wù)調(diào)度與數(shù)據(jù)傳輸
并發(fā)隊列是實現(xiàn)生產(chǎn)者-消費者模式的核心。

- 阻塞隊列 (BlockingQueue)
- 特點:當(dāng)隊列滿時,插入操作會被阻塞;當(dāng)隊列空時,獲取操作會被阻塞。
- 核心實現(xiàn):
ArrayBlockingQueue:由數(shù)組實現(xiàn)的有界阻塞隊列。內(nèi)部使用一個可重入鎖和兩個條件變量(notEmpty, notFull)來實現(xiàn)阻塞。LinkedBlockingQueue:由鏈表實現(xiàn)的可選有界阻塞隊列。默認(rèn)無界,但可設(shè)置容量。采用兩把鎖(putLock, takeLock),讀寫操作可以完全并行,吞吐量通常高于ArrayBlockingQueue。PriorityBlockingQueue:支持優(yōu)先級的無界阻塞隊列。SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等待另一個線程的對應(yīng)移除操作,反之亦然。非常適合直接傳遞任務(wù)的場景,吞吐量很高。
- 非阻塞隊列
ConcurrentLinkedQueue- 特點:基于鏈表實現(xiàn)的無界非阻塞隊列。采用CAS算法實現(xiàn),保證了線程安全。
- 適用場景:適用于對性能要求極高,且可以容忍
poll()獲取元素時返回null(隊列為空)的場景。
3. 并發(fā)List與Set
CopyOnWriteArrayList(COW) - 寫時復(fù)制列表- 實現(xiàn)原理:所有修改操作(add, set, remove)都會復(fù)制底層數(shù)組。讀操作在原數(shù)組上進(jìn)行,因此讀操作極快且無需加鎖。修改操作完成后,將原數(shù)組引用指向新數(shù)組。
- 優(yōu)缺點:
- 優(yōu)點:讀性能極高,完全無鎖。
- 缺點:內(nèi)存占用大(每次修改都復(fù)制整個數(shù)組);數(shù)據(jù)弱一致性(讀操作可能無法立即讀到剛寫入的數(shù)據(jù))。
- 適用場景:讀多寫少的極致場景,如監(jiān)聽器列表、配置信息的存儲。
CopyOnWriteArraySet- 實現(xiàn)原理:內(nèi)部封裝了一個
CopyOnWriteArrayList,因此特性與COW列表完全一致。 - 適用場景:讀多寫少且需要集合語義的場景。
- 實現(xiàn)原理:內(nèi)部封裝了一個
4. 并發(fā)工具類(擴展)
雖然不嚴(yán)格屬于集合,但常與并發(fā)集合配合使用。
ConcurrentSkipListSet:基于ConcurrentSkipListMap實現(xiàn)的有序并發(fā)Set。BlockingDeque:雙端阻塞隊列接口,代表實現(xiàn)是LinkedBlockingDeque。
三、選型指南:如何選擇合適的并發(fā)容器?
選擇正確的并發(fā)容器是優(yōu)化性能的關(guān)鍵。
| 場景 | 推薦容器 | 理由 |
|---|---|---|
| 高頻鍵值存取 | ConcurrentHashMap | 高并發(fā)、低延遲,全能選手 |
| 有序的鍵值存取 | ConcurrentSkipListMap | 線程安全且有序 |
| 生產(chǎn)者-消費者模式 | ArrayBlockingQueue / LinkedBlockingQueue | 天然的阻塞特性,完美適配 |
| 直接任務(wù)傳遞 | SynchronousQueue | 高吞吐量的任務(wù)交接 |
| 極高的讀頻率,極少寫 | CopyOnWriteArrayList / CopyOnWriteArraySet | 讀操作無鎖,性能無敵 |
| 高性能非阻塞隊列 | ConcurrentLinkedQueue | CAS實現(xiàn),避免鎖開銷 |
重要原則:
- 優(yōu)先使用JUC容器,而不是用
Collections.synchronizedXXX()來包裝舊容器。 - 明確需求:是需要Map、Queue還是List?是否需要阻塞特性?是否需要有序?
- 考慮讀寫比例:
CopyOnWrite系列只在寫極少的情況下有優(yōu)勢。 - 理解實現(xiàn)原理:了解底層是使用鎖還是CAS,有助于你判斷其在高競爭下的性能表現(xiàn)。
到此這篇關(guān)于Java JUC并發(fā)集合詳解:線程安全容器完全指南的文章就介紹到這了,更多相關(guān)Java JUC并發(fā)集合內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中Object toString方法簡介_動力節(jié)點Java學(xué)院整理
Object類在Java里面是一個比較特殊的類,JAVA為了組織這個類組織得比較方便,它提供了一個最根上的類,相當(dāng)于所有的類都是從這個類繼承,這個類就叫Object。接下來通過本文給大家介紹Object toString方法,需要的的朋友參考下吧2017-05-05
詳解Spring batch 入門學(xué)習(xí)教程(附源碼)
本篇文章主要介紹了Spring batch 入門學(xué)習(xí)教程(附源碼),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
使用@PropertySource讀取配置文件通過@Value進(jìn)行參數(shù)注入
這篇文章主要介紹了使用@PropertySource讀取配置文件通過@Value進(jìn)行參數(shù)注入,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

