一、Java線程的概念
Java 線程的本質:每個線程對應一個操作系統線程,由操作系統調度。JVM 通過調用操作系統 API(如 Linux 的 pthread
)創建線程。
關鍵點:
? 用戶態與內核態:線程調度依賴操作系統(內核級線程),能直接利用多核 CPU。
? 線程生命周期:新建 → 就緒 → 運行 → 阻塞 → 終止。
? JVM 線程模型:每個 Java 線程對應一個 Thread
對象,通過 start()
觸發操作系統線程的創建。
二、線程的使用方法
方式 1:繼承 Thread
類(簡單但不夠靈活)
class MyThread extends Thread {@Overridepublic void run() {System.out.println("線程執行: " + Thread.currentThread().getName());}
}// 使用
MyThread t = new MyThread();
t.start(); // 注意:必須調用 start(),而不是直接 run()
方式 2:實現 Runnable
接口(推薦,避免單繼承限制)
class MyTask implements Runnable {@Overridepublic void run() {System.out.println("任務執行: " + Thread.currentThread().getName());}
}// 使用
Thread t = new Thread(new MyTask());
t.start();
方式 3:帶返回值的 Callable
(適合需要結果的任務)
? Callable
:帶返回值的任務(像“下單”),比如 Callable<String>
表示這個任務最終會返回一個 String
。
? Future
:代表異步任務的“憑證”(像“訂餐小票”),憑它未來可以取結果。
以訂餐流程舉例:
- 提交任務:你去餐廳點了一份炒飯,服務員給你一張小票(
Future
)。 - 后廚做菜:廚師(線程池中的線程)開始炒飯(執行
Callable
)。 - 等待結果:你可以干其他事情(不阻塞主線程),也可以隨時拿小票問:“好了沒?”(
future.isDone()
)。 - 取回結果:當炒飯做好后,憑小票取餐(
future.get()
拿到返回值)。
Future底層實現原理:
-
狀態跟蹤:
Future
內部維護任務狀態:
? 未完成:任務還在執行。
? 已完成:任務正常結束,保存返回值。
? 已取消:任務被中斷。
? 異常結束:保存拋出的異常。 -
阻塞獲取:當調用
future.get()
時:
? 如果任務已完成 → 直接返回結果。
? 如果未完成 → 當前線程阻塞等待,直到任務完成(內部通過wait/notify
機制實現)。 -
結果存儲:任務完成后,返回值(或異常)會被存入
Future
內部的成員變量,供后續讀取。
代碼示例:
import java.util.concurrent.*;public class FutureExample {public static void main(String[] args) throws Exception {// 1. 創建線程池(后廚)ExecutorService executor = Executors.newSingleThreadExecutor();// 2. 提交 Callable 任務(下單炒飯)Future<String> future = executor.submit(new Callable<String>() {@Overridepublic String call() throws Exception {Thread.sleep(2000); // 模擬炒飯需要2秒return "揚州炒飯做好了!";}});System.out.println("提交任務后,主線程繼續做其他事情...");// 3. 檢查是否完成(非阻塞)if (future.isDone()) {System.out.println("任務已經完成!");} else {System.out.println("任務還在進行中...");}// 4. 阻塞獲取結果(類似等待取餐)String result = future.get(); // 這里會阻塞,直到任務完成System.out.println("取到結果:" + result);executor.shutdown(); // 關閉線程池(后廚下班)}
}
輸出:
提交任務后,主線程繼續做其他事情...
任務還在進行中...
(等待2秒后)
取到結果:揚州炒飯做好了!
- 異常處理:
如果任務中拋出異常,future.get()
會拋出ExecutionException
,可通過getCause()
獲取原始異常:
try {future.get();
} catch (ExecutionException e) {System.out.println("任務出錯:" + e.getCause());
}
- 超時控制:
避免無限等待,可以設置超時時間:
String result = future.get(3, TimeUnit.SECONDS); // 最多等3秒
- 取消任務:
如果不想等了,可以取消任務:
future.cancel(true); // true表示嘗試中斷正在執行的任務
三、Java 線程池機制詳解
線程池的核心思想
? 復用線程:避免頻繁創建/銷毀線程的開銷(類似餐廳固定幾個服務員服務所有顧客,而不是每來一個顧客就雇傭新服務員)。
? 資源管控:通過隊列緩沖任務,防止系統過載(類似餐廳的等候區,避免人太多擠爆店面)。
線程池的四大核心參數
ThreadPoolExecutor(int corePoolSize, // 核心線程數(常駐員工)int maximumPoolSize, // 最大線程數(臨時工上限)long keepAliveTime, // 空閑線程存活時間(臨時工多久沒活就解雇)TimeUnit unit, // 時間單位BlockingQueue<Runnable> workQueue, // 任務隊列(等候區座位數)RejectedExecutionHandler handler // 拒絕策略(人滿時怎么處理新顧客)
)
參數詳解:
- corePoolSize:核心線程即使空閑也不會被銷毀(除非設置
allowCoreThreadTimeOut
)。 - maximumPoolSize:當隊列滿時,允許創建的最大線程數(核心線程 + 臨時線程)。
- workQueue:常用隊列類型:
? ArrayBlockingQueue:有界隊列(固定容量)。
? LinkedBlockingQueue:無界隊列(默認Integer.MAX_VALUE
,慎用易內存溢出)。
? SynchronousQueue:不存儲任務,直接移交(適合瞬時高并發)。 - 拒絕策略(當隊列和線程池全滿時):
? AbortPolicy:拋異常(默認)。
? CallerRunsPolicy:讓提交任務的線程自己執行。
? DiscardPolicy:默默丟棄新任務。
? DiscardOldestPolicy:丟棄隊列最舊的任務,再嘗試提交。
合理設置線程數:
? CPU密集型:線程數 ≈ CPU核數(避免過多上下文切換)。
? IO密集型:線程數 ≈ CPU核數 * 2(或更高,因線程常阻塞在IO)。
監控線程池狀態:
// 查看活躍線程數
int activeCount = executor.getActiveCount();
// 查看任務隊列大小
int queueSize = executor.getQueue().size();
線程池的工作流程
↗ 核心線程有空 → 立即執行
任務提交 → 檢查核心線程↘ 核心線程忙 → 入隊列 → 隊列滿? → 否 → 等待↘ 是 → 創建臨時線程 → 超過最大數? → 是 → 拒絕
常用線程池(通過 Executors
工廠創建)
1. FixedThreadPool(固定大小團隊)
ExecutorService fixedPool = Executors.newFixedThreadPool(4); // 4個核心線程
? 特點:核心線程=最大線程,無臨時線程,使用無界隊列(LinkedBlockingQueue
)。
? 適用場景:已知并發量且任務耗時較長(如后臺計算)。
2. CachedThreadPool(彈性團隊)
ExecutorService cachedPool = Executors.newCachedThreadPool();
? 特點:核心線程=0,最大線程=Integer.MAX_VALUE,空閑線程60秒回收,使用 SynchronousQueue
(直接移交任務)。
? 適用場景:短時高頻小任務(如HTTP請求處理)。
3. SingleThreadExecutor(單人團隊)
ExecutorService singlePool = Executors.newSingleThreadExecutor();
? 特點:核心線程=最大線程=1,無界隊列,保證任務順序執行。
? 適用場景:需要順序執行的任務(如日志寫入)。
4. ScheduledThreadPool(計劃任務團隊)
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);
// 延遲3秒執行
scheduledPool.schedule(() -> System.out.println("Run after 3s"), 3, TimeUnit.SECONDS);
// 固定頻率執行(每隔1秒)
scheduledPool.scheduleAtFixedRate(() -> System.out.println("Run every 1s"), 0, 1, TimeUnit.SECONDS);
? 特點:支持定時、周期性任務。
? 適用場景:心跳檢測、定時數據同步。
5. 自定義線程池
public class ThreadPoolDemo {public static void main(String[] args) {// 創建線程池:2核心線程,5最大線程,10容量隊列,拒絕策略拋異常ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),new ThreadPoolExecutor.AbortPolicy());// 提交20個任務(測試隊列滿時的擴容)for (int i = 0; i < 20; i++) {final int taskId = i;try {executor.submit(() -> {System.out.println("任務 " + taskId + " 由線程 " + Thread.currentThread().getName() + " 執行");try { Thread.sleep(1000); } catch (InterruptedException e) {}});} catch (RejectedExecutionException e) {System.out.println("任務 " + taskId + " 被拒絕!");}}executor.shutdown(); // 平滑關閉(等待已有任務完成)}
}
輸出分析:
? 前2個任務由核心線程立即執行。
? 接下來的10個任務進入隊列。
? 當隊列滿后(10個),創建3個臨時線程(總線程數=5)。
? 第18個任務提交時,線程數已達最大(5),隊列滿(10),觸發拒絕策略拋異常。
場景 | 推薦線程池 | 參數要點 |
---|---|---|
長期穩定并發任務 | FixedThreadPool | 核心線程數=最大線程數,隊列容量適中 |
短期突發小任務 | CachedThreadPool | 注意防止無限創建線程(適合可控的短任務) |
單線程順序執行 | SingleThreadExecutor | 替代手動創建線程,保證順序性 |
定時/周期性任務 | ScheduledThreadPool | 指定延遲和周期 |
高并發自定義需求 | ThreadPoolExecutor | 根據業務特點調整核心參數 |
線程池關閉方法
- shutdown():平滑關閉,不再接受新任務,等待已有任務完成。
- shutdownNow():立刻停止所有任務,返回未執行的任務列表。
List<Runnable> unfinishedTasks = executor.shutdownNow();
四、線程同步與安全,原理、用法及示例
在多線程環境下,當多個線程同時訪問共享資源(如變量、文件、數據庫)時,可能導致數據不一致或邏輯錯誤。線程同步的目的是協調線程間的執行順序,確保線程安全。
詳細參考:https://blog.csdn.net/gengzhikui1992/article/details/147230900?spm=1001.2014.3001.5501
常見同步方式及底層原理
1. synchronized
關鍵字:
? 原理:基于對象的內置鎖(Monitor),每個對象關聯一個Monitor。
執行synchronized
代碼時,線程需獲取對象的Monitor鎖:
? 成功則持有鎖,執行代碼。
? 失敗時線程進入鎖的等待隊列(EntrySet),阻塞等待喚醒。
? 用法:
// 同步方法
public synchronized void safeMethod() { /* ... */ }// 同步代碼塊
public void someMethod() {synchronized (this) { // 鎖對象為當前實例// 臨界區代碼}
}
? 示例:
class Counter {private int count = 0;public synchronized void increment() {count++; // 原子操作}
}
解析:synchronized
確保同一時刻僅一個線程執行increment()
方法。
2. ReentrantLock
可重入鎖:
? 原理:基于AQS(AbstractQueuedSynchronizer),維護一個CLH隊列管理等待線程。
支持可重入性(同一線程可多次加鎖)和公平性(可選)。
? 用法:
private final ReentrantLock lock = new ReentrantLock();public void safeMethod() {lock.lock(); // 手動加鎖try {// 臨界區代碼} finally {lock.unlock(); // 必須手動釋放}
}
? 示例(帶超時):
if (lock.tryLock(1, TimeUnit.SECONDS)) { // 嘗試1秒內獲取鎖try { /* ... */ } finally { lock.unlock(); }
} else { // 超時處理 }
優勢:比synchronized
更靈活,支持嘗試鎖、公平鎖等。
特性 | synchronized | ReentrantLock |
---|---|---|
鎖的獲取方式 | 自動獲取和釋放(JVM管理) | 手動 lock() 和 unlock() (需寫finally) |
可中斷性 | 不支持(阻塞時無法中斷) | 支持 lockInterruptibly() |
超時機制 | 不支持(只能阻塞等待) | 支持 tryLock(timeout) |
公平鎖 | 僅非公平鎖 | 支持公平和非公平(構造參數控制) |
條件變量 | 只能綁定一個條件(wait() /notify() ) | 可創建多個條件(newCondition() ) |
性能 | JDK6后優化后性能接近 | 高并發競爭時性能更好 |
代碼復雜度 | 簡單(自動管理) | 復雜(需手動釋放,易忘) |
鎖的可見性 | 通過JVM內存模型保證 | 基于AQS的volatile變量保證 |
? synchronized
的優勢:簡單、安全、自動釋放鎖,適合快速開發。
? ReentrantLock
的優勢:靈活、功能強大,適合需要超時、中斷、公平鎖等復雜場景。
最終建議:優先用 synchronized
,遇到它無法滿足需求時再考慮 ReentrantLock
。
3. volatile
變量:
多線程環境下,變量操作可能引發兩種問題:
- 可見性問題:A線程修改了變量,B線程看不到最新值。
- 原子性問題:看似一步的操作(如
i++
),實際分三步(讀-改-寫),中間可能被其他線程打斷。
volatile 變量:解決了可見性問題,原理:通過內存屏障禁止指令重排序,確保變量的修改對所有線程立即可見(不保證原子性)。
? 強制讀寫主內存:volatile
變量修改后,其他線程立即可見。
? 禁止指令重排序:確保代碼執行順序符合預期。
使用場景
適合做 狀態標志(如開關控制),不涉及復雜計算。
public class Server {private volatile boolean isRunning = true; // 狀態標志public void stop() {isRunning = false; // 修改后,其他線程立即可見}public void run() {while (isRunning) { // 循環讀取最新值// 處理請求...}}
}
局限性
? 不保證原子性:volatile
無法解決 i++
這種非原子操作的問題。
volatile int count = 0;
count++; // 實際分三步:讀 -> 改 -> 寫(線程不安全!)
4. 原子類(Atomic Classes):解決原子性問題
? 封裝原子操作:通過 CPU 的 CAS(Compare-And-Swap) 指令,保證操作的原子性。
? 無需加鎖:性能優于 synchronized
。
常見類
? AtomicInteger
、AtomicLong
:整型原子操作。
? AtomicReference
:對象引用原子操作。
? AtomicStampedReference
:解決 ABA 問題(版本號控制)。
使用場景
適合 計數器、累加器 等需要原子操作的場景。
public class Counter {private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet(); // 原子自增}public int get() {return count.get();}
}
示例:AtomicReference 保證對象引用原子性
public class AtomicReferenceDemo {private AtomicReference<String> latestMessage = new AtomicReference<>("");public void updateMessage(String message) {latestMessage.set(message); // 原子更新引用}public String getMessage() {return latestMessage.get();}
}
示例:解決 ABA 問題(AtomicStampedReference)
public class ABADemo {private AtomicStampedReference<Integer> atomicValue = new AtomicStampedReference<>(100, 0); // 初始值100,版本號0public void update() {int[] stampHolder = new int[1];int currentValue = atomicValue.get(stampHolder); // 獲取值和版本號int newValue = currentValue + 1;atomicValue.compareAndSet(currentValue, newValue, stampHolder[0], stampHolder[0] + 1);}
}
特性 | volatile | 原子類(如 AtomicInteger) |
---|---|---|
解決可見性問題 | ??(強制主內存讀寫) | ??(內部使用 volatile 變量) |
解決原子性問題 | ?(如 i++ 仍不安全) | ??(封裝原子操作) |
性能 | 高(無鎖) | 高(CAS 無鎖) |
適用場景 | 狀態標志、開關控制 | 計數器、累加器、復雜原子操作 |
ABA 問題 | 無法解決 | 可通過 AtomicStampedReference 解決 |
? volatile
是輕量級的可見性解決方案,不保證原子性。
? 原子類通過 CAS 實現無鎖原子操作,同時解決可見性和原子性。
? 兩者性能均優于鎖,但適用場景不同,不要混淆!
-
用
volatile
:
? 變量被多個線程共享,但只有一個線程修改它。
? 需要立即可見性,但不涉及復合操作(如i++
)。
? 典型場景:狀態標志(boolean
開關)。 -
用原子類:
? 變量被多個線程頻繁修改(如計數器)。
? 需要原子性操作(如addAndGet()
、compareAndSet()
)。
? 典型場景:并發計數器、無鎖數據結構。 -
用
synchronized
或ReentrantLock
:
? 需要同步多步操作(如先讀后寫)。
? 原子類和volatile
無法滿足復雜邏輯時。
6. 讀寫鎖 ReentrantReadWriteLock
:
想象一個圖書館:
? 讀鎖:允許多個人同時讀書(共享資源)。
? 寫鎖:當有人要修改書的內容時,必須清場(獨占資源),其他人不能讀也不能寫。
核心規則:
- 讀鎖之間不互斥:多個線程可以同時持有讀鎖。
- 寫鎖與其他鎖互斥:寫鎖生效時,其他線程不能獲取讀鎖或寫鎖。
- 寫鎖優先:如果寫鎖在等待,新來的讀鎖會被阻塞(防止“寫線程饑餓”)。
為什么用讀寫鎖?
在 讀多寫少 的場景下(如緩存系統、配置管理),用讀寫鎖比普通互斥鎖(如 synchronized
)性能更高:
? 讀操作:允許多線程并發讀取。
? 寫操作:保證獨占修改,避免數據不一致。
場景:實現一個線程安全的緩存系統
public class Cache<K, V> {private final Map<K, V> cacheMap = new HashMap<>();private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();private final Lock readLock = rwLock.readLock(); // 讀鎖private final Lock writeLock = rwLock.writeLock(); // 寫鎖// 讀操作:允許多線程并發讀public V get(K key) {readLock.lock();try {return cacheMap.get(key);} finally {readLock.unlock();}}// 寫操作:獨占訪問public void put(K key, V value) {writeLock.lock();try {cacheMap.put(key, value);} finally {writeLock.unlock();}}// 復雜操作:先讀后寫(需要先釋放讀鎖,再獲取寫鎖)public void updateIfPresent(K key, V newValue) {readLock.lock();try {if (cacheMap.containsKey(key)) {// 釋放讀鎖,獲取寫鎖(注意:不能直接升級鎖!)readLock.unlock();writeLock.lock();try {cacheMap.put(key, newValue);} finally {writeLock.unlock();}// 重新獲取讀鎖(如果需要)readLock.lock();}} finally {readLock.unlock();}}
}
關鍵細節
- 避免鎖升級:先釋放讀鎖,再獲取寫鎖。
- 寫鎖優先:如果寫鎖在等待,后續讀鎖會被阻塞(可通過公平鎖緩解)。
- 鎖的釋放:必須用
try-finally
確保釋放,否則會導致死鎖。
在持有寫鎖時,可以獲取讀鎖,然后釋放寫鎖(保持數據可見性):
public void writeThenRead() {writeLock.lock();try {// 修改數據...readLock.lock(); // 鎖降級(允許)} finally {writeLock.unlock();}try {// 讀取數據...} finally {readLock.unlock();}
}
不能直接從讀鎖升級到寫鎖(會導致死鎖):
public void readThenWrite() {readLock.lock();try {// 如果發現需要修改數據...writeLock.lock(); // 錯誤!會阻塞,因為讀鎖未釋放,其他線程也無法釋放寫鎖} finally {readLock.unlock();}
}
線程同步方式的對比與選擇
方式 | 原理 | 適用場景 | 性能 |
---|---|---|---|
synchronized | 對象內置鎖 | 簡單同步,少量競爭 | 中等,自動釋放鎖 |
ReentrantLock | AQS隊列鎖 | 復雜控制(如超時、公平鎖) | 高,需手動釋放 |
volatile | 內存可見性 | 單變量狀態標志 | 極高,無鎖 |
原子類 | CAS指令 | 計數器,單變量原子操作 | 高,無鎖競爭 |
ReentrantReadWriteLock | 讀寫分離鎖 | 讀多寫少場景 | 讀高,寫中等 |
- 優先選擇高級工具:如
java.util.concurrent
包下的并發集合(ConcurrentHashMap
,BlockingQueue
)。 - 避免鎖粒度過大:盡量縮小同步范圍,減少競爭。
- 資源釋放:使用
Lock
時務必在finally
中釋放鎖。 - 分工協作:讀寫分離時使用
ReentrantReadWriteLock
提升性能。 - 監測工具:利用
jstack
和VisualVM
排查死鎖和性能瓶頸。
五、Java線程安全集合詳解
Java提供了多種線程安全的集合類,適用于高并發場景。它們通過內部優化(如分段鎖、寫時復制)實現高效并發,避免開發者手動加鎖。以下是常見線程安全集合及其使用場景和示例:
1. ConcurrentHashMap(并發哈希表)
? 原理:將數據分為多個段(Segment,Java 8后改為Node數組+CAS),每個段獨立加鎖。允許多線程同時讀寫不同段的數據。
? 適用場景:高并發鍵值存儲(如緩存、計數器)。
? 示例:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();// 線程安全的插入(若key不存在)
map.putIfAbsent("apple", 1);// 原子累加操作
map.compute("apple", (k, v) -> v == null ? 1 : v + 1);// 遍歷(弱一致性迭代器,不拋ConcurrentModificationException)
map.forEach((k, v) -> System.out.println(k + ": " + v));
2. CopyOnWriteArrayList(寫時復制列表)
? 原理:寫操作時復制整個數組(加鎖保證原子性),讀操作無鎖。適合讀多寫少的場景。
? 適用場景:監聽器列表、配置信息列表。
? 示例:
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("user1");// 讀操作無需加鎖
for (String user : list) {System.out.println(user);
}// 寫操作會復制新數組
list.add("user2"); // 原數組:[user1],新數組:[user1, user2]
3. BlockingQueue(阻塞隊列)
? 原理:當隊列空時阻塞消費者,隊列滿時阻塞生產者。內部通過ReentrantLock
和Condition
實現。
? 常見實現:
? ArrayBlockingQueue:有界隊列(數組實現)。
? LinkedBlockingQueue:可選有界或無界(鏈表實現)。
? PriorityBlockingQueue:優先級阻塞隊列。
? 適用場景:生產者-消費者模型。
? 示例:
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);// 生產者
new Thread(() -> {try {queue.put("task1"); // 隊列滿時阻塞} catch (InterruptedException e) {e.printStackTrace();}
}).start();// 消費者
new Thread(() -> {try {String task = queue.take(); // 隊列空時阻塞System.out.println("處理任務: " + task);} catch (InterruptedException e) {e.printStackTrace();}
}).start();
4. ConcurrentLinkedQueue(并發鏈表隊列)
? 原理:基于無鎖算法(CAS),實現非阻塞線程安全隊列。
? 適用場景:高并發非阻塞隊列(如任務分發)。
? 示例:
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();// 生產者
queue.offer(100); // 非阻塞添加// 消費者
Integer value = queue.poll(); // 非阻塞取出
5. ConcurrentSkipListMap(并發跳表映射)
? 原理:基于跳表(Skip List)數據結構,實現有序的并發Map。
? 適用場景:需要排序的高并發鍵值存儲(如排行榜)。
? 示例:
ConcurrentSkipListMap<Integer, String> rank = new ConcurrentSkipListMap<>();
rank.put(90, "Alice");
rank.put(85, "Bob");// 按分數從高到低遍歷
rank.descendingMap().forEach((score, name) -> {System.out.println(name + ": " + score);
});
6. CopyOnWriteArraySet(寫時復制集合)
? 原理:基于CopyOnWriteArrayList
實現,用數組存儲元素,寫操作時復制。
? 適用場景:讀多寫少的集合(如IP白名單)。
? 示例:
CopyOnWriteArraySet<String> ips = new CopyOnWriteArraySet<>();
ips.add("192.168.1.1");// 檢查IP是否存在(無需加鎖)
if (ips.contains("192.168.1.1")) {System.out.println("IP允許訪問");
}
7. Collections.synchronizedXXX(同步包裝類)
? 原理:通過包裝普通集合,對所有方法加synchronized
鎖。
? 適用場景:低并發環境(性能低于專用并發集合)。
? 示例:
List<String> syncList = Collections.synchronizedList(new ArrayList<>());// 遍歷時需手動加鎖
synchronized (syncList) {for (String item : syncList) {System.out.println(item);}
}
線程安全集合對比表
集合名稱 | 原理 | 適用場景 | 性能特點 |
---|---|---|---|
ConcurrentHashMap | 分段鎖/CAS | 高并發鍵值存儲 | 高吞吐量,低延遲 |
CopyOnWriteArrayList | 寫時復制 | 讀多寫少的列表 | 寫操作慢,讀操作快 |
BlockingQueue | 鎖+條件隊列 | 生產者-消費者模型 | 阻塞操作,適用于任務調度 |
ConcurrentLinkedQueue | 無鎖(CAS) | 高并發非阻塞隊列 | 高并發,無鎖 |
ConcurrentSkipListMap | 跳表 | 有序并發鍵值存儲 | 查詢和插入O(log n) |
CopyOnWriteArraySet | 基于CopyOnWriteArrayList | 讀多寫少的集合 | 同CopyOnWriteArrayList |
-
鍵值存儲:
? 高并發寫入:ConcurrentHashMap
? 需要排序:ConcurrentSkipListMap
-
列表/集合:
? 讀多寫少:CopyOnWriteArrayList
/CopyOnWriteArraySet
? 寫操作頻繁:使用ConcurrentHashMap
模擬(如Collections.newSetFromMap
) -
隊列:
? 阻塞隊列:ArrayBlockingQueue
/LinkedBlockingQueue
? 非阻塞隊列:ConcurrentLinkedQueue