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

Java 多線程並發編程核心要點深度解析:從 synchronized 到 JUC 的完整知識體系

     編輯:Java 相關知識

前言

Java 多線程並發是後端開發的核心硬功夫,涉及記憶體模型 (JMM)、鎖機制、線程協作、無鎖演算法、並發容器等深層機制。本文系統性構建從 synchronized 到 JUC 的完整知識體系,聚焦核心原理、常見陷阱、最佳實務與面試高頻考點。

基石:Java 記憶體模型 (JMM)

線程工作記憶體 (Thread Local Memory)     主記憶體 (Main Memory)
┌─────────────────────────┐               ┌─────────────────────────┐
│  共享變量副本 (x=10)    │ ◄──────────▶  │  共享變量主值 (x=10)    │
│  執行引擎               │   load/store  │  堆內存                 │
└─────────────────────────┘               └─────────────────────────┘

三大特性

happens-before 關鍵規則

  1. 程式順序規則:單線程內按代碼順序
  2. 鎖規則:unlock happens-before 後續 lock
  3. volatile 規則:寫 happens-before 後續讀
  4. 線程啟動規則:start() happens-before 線程內動作
  5. 線程終止規則:線程內動作 happens-before join() 返回
  6. 中斷規則:interrupt() happens-before 被中斷線程檢測到
  7. 傳遞性:A hb B, B hb C ⇒ A hb C

synchronized 深度解析

三種鎖定形式

// 1. 實例方法鎖:鎖當前對象 this
public synchronized void instanceMethod() { }

// 2. 靜態方法鎖:鎖 Class 對象
public static synchronized void staticMethod() { }

// 3. 同步代碼塊:鎖指定對象
public void blockSync() {
    synchronized (this) { }           // 鎖 this
    synchronized (MyClass.class) { }  // 鎖 Class
    synchronized (sharedObject) { }   // 鎖共享對象
}

鎖升級機制 (JDK 6+ 偏向鎖 → 輕量級鎖 → 重量級鎖)

特性定義實現機制
可見性一線程寫入,其他線程可見volatile、synchronized、final、JUC 類
有序性程式順序 vs 執行順序volatile (禁止重排)、synchronized (鎖序)、happens-before
原子性操作不可分割synchronized、Lock、AtomicXXX、CAS
鎖狀態適用場景實現性能
無鎖無併發無最快
偏向鎖單線程重複獲取CAS 設置 ThreadID 到 Mark Word極快 (無同步開銷)
輕量級鎖多線程交替、低爭用CAS 將 Mark Word 指向棧鎖記錄快 (自旋)
重量級鎖高爭用、長持有OS Mutex、線程阻塞/喚醒慢 (上下文切換)

經典錯誤:鎖對象不一致

// ❌ 錯誤:每次 new 新對象,鎖無效
public void wrong() {
    synchronized (new Object()) { // 每次鎖不同對象!
        criticalSection();
    }
}

// ✅ 正確:共享不可變對象
private final Object lock = new Object();
public void correct() {
    synchronized (lock) {
        criticalSection();
    }
}

// ✅ 正確:實例方法鎖 this (同一實例)
public synchronized void alsoCorrect() { }

wait/notify 機制與生產者消費者

class BoundedBuffer {
    private final Object[] items = new Object[10];
    int putIdx = 0, takeIdx = 0, count = 0;
    
    public synchronized void put(Object item) throws InterruptedException {
        while (count == items.length) wait(); // 滿則等待
        items[putIdx] = item;
        putIdx = (putIdx + 1) % items.length;
        count++;
        notifyAll(); // 喚醒消費者
    }
    
    public synchronized Object take() throws InterruptedException {
        while (count == 0) wait(); // 空則等待
        Object item = items[takeIdx];
        items[takeIdx] = null;
        takeIdx = (takeIdx + 1) % items.length;
        count--;
        notifyAll(); // 喚醒生產者
        return item;
    }
}

關鍵點:wait() 必須在 synchronized 內調用,釋放鎖並進入 WAITING;notifyAll() 唤醒所有等待線程,重新競爭鎖。

Lock 框架:ReentrantLock 進階特性

class ReentrantLockDemo {
    private final ReentrantLock lock = new ReentrantLock(true); // 公平鎖
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    
    public void put(Object item) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) notFull.await(); // 精確喚醒
            // ... 放入邏輯
            notEmpty.signal();
        } finally {
            lock.unlock(); // 必須在 finally 釋放
        }
    }
}

優於 synchronized 特性

  • 可中斷獲取:lock.lockInterruptibly() 響應中斷
  • 超時獲取:lock.tryLock(timeout, unit) 避免死等
  • 公平鎖選項:new ReentrantLock(true) 先來先得
  • 多條件變數:newCondition() 精確喚醒 (生產者/消費者分離)
  • 可查詢狀態:isLocked(), getHoldCount(), getQueueLength()

volatile 關鍵字:輕量級同步

class VolatileDemo {
    private volatile boolean running = true; // 可見性 + 禁止指令重排
    private volatile int counter = 0;        // 單次寫入原子,複合操作非原子
    
    public void stop() { running = false; }
    
    // ❌ 非原子:讀-改-寫三步驟
    public void increment() { counter++; } 
    
    // ✅ 原子:用 AtomicInteger
    private final AtomicInteger atomicCounter = new AtomicInteger(0);
    public void atomicIncrement() { atomicCounter.incrementAndGet(); }
}

線程池與 Executor 體系 (JUC 核心)

// 生產級配置模板
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(queueCapacity), // 有界隊列防 OOM
    new NamedThreadFactory("biz-"),          // 線程命名
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略:呼叫者執行
);

// 關閉流程
executor.shutdown(); // 不接受新任務,處理完隊列
try {
    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow(); // 強制關閉,返回未執行任務
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
    Thread.currentThread().interrupt();
}

並發容器選型指南

容器適用場景核心技術
ConcurrentHashMap高併發 MapJDK 8: CAS + Node + synchronized (bin 首節點)
CopyOnWriteArrayList讀多寫少、遍歷無鎖寫時複製數組、快照迭代器
BlockingQueue生產者消費者ReentrantLock + Condition (Array/Linked/Delay/Priority)
ConcurrentLinkedQueue無界非阻塞隊列CAS 無鎖鏈表
LongAdder高併發計數器分段累加 (Cell[]),sum() 時聚合

CompletableFuture 異步編程 (JDK 8+)

// 串聯
CompletableFuture.supplyAsync(() -> fetchUser(id))
    .thenApply(user -> enrich(user))
    .thenAccept(enriched -> cache.put(enriched))
    .exceptionally(ex -> { log.error("失敗", ex); return null; });

// 並行聚合
CompletableFuture.allOf(
    supplyAsync(() -> serviceA.call()),
    supplyAsync(() -> serviceB.call()),
    supplyAsync(() -> serviceC.call())
).join(); // 等待全部完成

// 異步回調扁平化
supplyAsync(() -> fetchUser(id))
    .thenCompose(user -> supplyAsync(() -> fetchOrders(user.id)))
    .thenAccept(orders -> render(orders));

死鎖與活鎖預防

  1. 固定鎖順序:全局規定獲取鎖的順序 (如按 hashCode 排序)
  2. 超時機制:lock.tryLock(timeout) 避免無限等待
  3. 避免嵌套鎖:重構減少持有鎖調用外部方法
  4. 死鎖檢測:jstack 分析、ThreadMXBean.findDeadlockedThreads()

面試高頻考點速查

問題核心答案
synchronized vs LockLock 提供可中斷、超時、公平、多 Condition、可查狀態
volatile 能否替代 synchronized不能:volatile 只保證可見性/有序性,不保證複合操作原子性
線程池參數如何設定CPU 密集:核心數+1;IO 密集:2*核心數;隊列有界;拒絕策略 CallerRuns
ConcurrentHashMap 1.7 vs 1.81.7 Segment 分段鎖;1.8 CAS + Node + synchronized (bin 首節點),更細粒度
ThreadLocal 記憶體洩漏原因Key 為弱引用,Value 強引用,Thread 不銷毀導致 Value 洩漏 → 用完 remove()
如何實現線程按序執行join()、CountDownLatch、CompletableFuture.thenCompose、單線程池

總結:並發編程成長路徑

  1. 基礎:掌握 synchronized/volatile/wait/notify/Thread 基礎 API
  2. 進階:理解 JMM、happens-before、鎖升級、線程池七參數、死鎖分析
  3. 實戰:熟練 JUC 容器、Lock、Condition、CompletableFuture、LongAdder、ThreadLocal
  4. 架構:無鎖設計、Actor 模型 (Akka)、CSP (Go Channel)、反應式流 (Reactor/RxJava)
  5. 診斷:Arthas、jstack、JMC、JFR、Async Profiler 定位併發瓶頸
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved