首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 高併發核心精講(五):JDK 並發包核心組件深度解析與源碼剖析

     編輯:Java 相關知識

前言

JDK java.util.concurrent(JUC)包是 Java 高併發編程的基石。本文系統講解 JUC 中核心同步器、併發容器的原理、用法與源碼實現,助你構建高效穩定的併發系統。

一、核心同步控制組件詳解

1.1 ReentrantLock:功能增強的互斥鎖

基本用法: 必須在 finally 中 unlock(),避免異常導致鎖永不釋放。

lock.lock();
try {
    // 臨界區操作
} finally {
    lock.unlock();
}

四大核心特性

特性說明關鍵 API
可重入同一線程可重複獲取鎖,計數器+1,需對應釋放次數內部實現
可中斷lockInterruptibly() 可響應中斷,解決死鎖利器lockInterruptibly()
可限時tryLock(timeout) 超時自動放棄,避免無限等待tryLock(long, TimeUnit)
公平鎖構造器 new ReentrantLock(true) 保證 FIFO 獲取鎖,犧牲吞吐量換公平構造器參數

死鎖檢測與中斷實戰


// 死鎖場景:線程1鎖A→等B,線程2鎖B→等A
// 解決:使用 lockInterruptibly() + 死鎖檢測線程中斷死鎖線程
ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
long[] deadlocked = mbean.findDeadlockedThreads();
if (deadlocked != null) {
    for (long id : deadlocked) {
        Thread.getAllStackTraces().keySet().stream()
            .filter(t -> t.getId() == id)
            .findFirst()
            .ifPresent(Thread::interrupt); // 中斷死鎖線程
    }
}

1.2 Condition:精準的線程協作

綁定 ReentrantLock,替代 Object.wait/notify,支持多條件隊列(如「不滿」「不空」)。

ReentrantLock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();

// 生產者
lock.lock();
try {
    while (queue.size() == capacity) notFull.await();
    queue.add(item);
    notEmpty.signal();
} finally { lock.unlock(); }

1.3 Semaphore:信號量控制並發度

允許 N 個線程同時進入臨界區,許可證耗盡則阻塞。許可證數=1 時退化為互斥鎖。

Semaphore semaphore = new Semaphore(5); // 允許 5 線程並發
semaphore.acquire(); // 獲取許可
try { /* 業務 */ } finally { semaphore.release(); }

1.4 ReadWriteLock:讀寫分離提升吞吐

核心語義: 讀讀共存、讀寫互斥、寫寫互斥。適用於「讀多寫少」場景。

ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();

// 讀操作
readLock.lock();
try { return data; } finally { readLock.unlock(); }

// 寫操作
writeLock.lock();
try { data = newValue; } finally { writeLock.unlock(); }

1.5 CountDownLatch:一次性倒計時門閂

主線程 await() 等待 N 個子線程 countDown() 歸零,**不可重用**。典型場景:火箭發射前多系統檢查。

1.6 CyclicBarrier:可重用的循環柵欄

N 線程 await() 歸零後觸發 barrierAction,**自動重置可重複使用**。典型場景:多階段任務同步(集合→出發→任務→集合)。

1.7 LockSupport:線程阻塞原語

基於「許可證」模型:park() 消費許可,unpark(thread) 產生許可。**解決 suspend/resume 死鎖缺陷**,支持中斷響應(不拋異常,通過 Thread.interrupted() 判斷)。

1.8 ReentrantLock 源碼核心架構

三大支柱:

  1. CAS 狀態: volatile int state 表示鎖狀態(0=釋放,1=持有,>1=重入次數)
  2. CLH 等待隊列: 雙向鏈表節點 Node,線程入隊自旋等待
  3. Park/Unpark: LockSupport.park(this) 掛起,unpark() 喚醒
// 獲取鎖核心邏輯
final void lock() {
    if (compareAndSetState(0, 1)) // CAS 嘗試獲取
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1); // 進入隊列排隊
}

// 隊列入隊 + 自旋 + Park
private final boolean acquireQueued(Node node, int arg) {
    while (true) {
        Node p = node.predecessor();
        if (p == head && tryAcquire(arg)) { // 嘗試獲取
            setHead(node);
            return false;
        }
        if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
            return true; // 中斷返回
    }
}

二、併發容器深度解析

2.1 ConcurrentHashMap:分段鎖 + CAS 的高併發 Map

JDK 7:Segment 分段鎖

  • 內部維護 Segment[] 數組,每個 Segment 繼承 ReentrantLock
  • put 先定位 Segment(高位 hash),再鎖定該 Segment 操作
  • 預設 16 段,**理論支持 16 線程並發寫入**
  • size() 需鎖定所有 Segment 求和,較重

JDK 8+:CAS + synchronized 節點鎖

  • 放棄 Segment,改用 Node[] 數組 + 鏈表/紅黑樹
  • putVal:CAS 嘗試插入頭節點 → 失敗則 synchronized(node) 鎖住鏈表頭節點
  • 擴容時多線程協助 transfer,**細粒度並發擴容**
  • size() 使用 LongAdder 累加器,高併發下極快

2.2 BlockingQueue:生產消費者模式標準實現

  • ArrayBlockingQueue:有界數組,鎖分離(takeLock/putLock)+ Condition
  • LinkedBlockingQueue:可選有界鏈表,頭尾節點分離鎖,吞吐極高
  • SynchronousQueue:無緩衝,直接移交,**線程池默認工作隊列**
  • PriorityBlockingQueue:優先級隊列,無界
  • DelayQueue:延遲隊列,基於 PriorityQueue + Leader-Follower 模式

三、總結與選型建議

組件核心適用場景關鍵注意點
ReentrantLock需要可中斷、超時、公平語義的互斥必須 finally unlock;高併發考慮 LongAdder/StampedLock
Condition多條件協作(如雙端隊列不滿/不空)必須在 lock 保護下 await/signal
Semaphore限流、資源池控制(連接池、線程池)許可證數量設定;acquire 可中斷
ReadWriteLock讀多寫少的共享數據結構寫線程饑風險;考慮 StampedLock
CountDownLatch一次性多線程等待彙聚不可重用;計數歸零後失效
CyclicBarrier多階段迭代任務同步可重用;barrierAction 異常會打破屏障
ConcurrentHashMap高併發 Map 存取JDK8+ 首選;複合操作需額外加鎖
BlockingQueue生產消費者解耦有界防 OOM;選擇正確實現類
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved