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

Java 多線程入門核心知識體系:創建方式、線程池、同步機制與避坑指南

     編輯:Java 相關知識

為什麼需要多線程?

  • 模型簡化:將獨立任務 (下載、計算、渲染) 拆分為並行線程,邏輯解耦。
  • UI 響應:Swing/JavaFX 事件分發線程 (EDT) 不被阻塞,界面保持流暢。
  • 多核利用:CPU 密集型任務並行執行,榨乾多核算力。
  • 異步處理:發送郵件、推送通知、日誌寫入等非關鍵路徑異步化,降低主流程延遲。

Java 線程特徵

  1. main 方法本身即主線程。
  2. 線程調度為搶佔式,執行順序不可預測 (非確定性)。
  3. 單線程內部指令按代碼順序順序執行 (happens-before)。
  4. 共享堆內存:實例字段、靜態字段、數組元素可見性需同步保證。

風險預警

風險類別典型表現後果
安全性競態條件、非原子操作、發布逸出數據錯誤、對象損壞、安全漏洞
活性死鎖、活鎖、飢餓程序卡死、吞吐為零
性能上下文切換、鎖爭用、偽共享、內存屏障開銷吞吐下降、延遲抖動、CPU 浪費

創建線程的兩種標準方式

1. 繼承 Thread 類

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Thread: " + i);
        }
    }
}
// 使用
new MyThread().start(); // 必須調用 start(),而非 run()

2. 實現 Runnable 接口 (推薦)

public class MyTask implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Runnable: " + i);
        }
    }
}
// 使用
new Thread(new MyTask()).start();
// 或配合線程池
executor.execute(new MyTask());

優勢:職責分離 (任務 vs 執行策略)、支援 Lambda、可提交給任意 Executor、避免單繼承限制。

線程池技術 (Executor 框架)

顏色創建銷毀線程開銷大、無限制創建導致 OOM,生產環境必須使用線程池。

Executors 工廠方法 (了解即可,生產慎用)

  • newFixedThreadPool(n):固定大小,隊列無界 (LinkedBlockingQueue),任務堆積風險。
  • newCachedThreadPool():可緩存,隊列 SynchronousQueue,線程數無上限 (Integer.MAX_VALUE),突發流量危險。
  • newSingleThreadExecutor():單線程串行,保證任務順序。
  • newScheduledThreadPool(n):定時/周期任務。

生產級自定義 ThreadPoolExecutor

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10,                    // corePoolSize
    50,                    // maximumPoolSize
    60L, TimeUnit.SECONDS, // keepAliveTime
    new LinkedBlockingQueue<>(1000), // 有界隊列,防 OOM
    new ThreadFactoryBuilder().setNameFormat("biz-worker-%d").build(), // 命名便於排查
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒絕策略:調用者執行,緩衝壓力
);
executor.execute(() -> System.out.println("Task running"));
executor.shutdown(); // 優雅關閉

關鍵參數選型原則

  • CPU 密集型:core = CPU 核心數 + 1,隊列較小。
  • IO 密集型:core = CPU 核心數 * 2 (或 * 1.5),隊列較大,最大線程數可更高。
  • 拒絕策略:CallerRunsPolicy (緩衝)、AbortPolicy (拋異常)、DiscardOldestPolicy (丟棄最舊)。

同步機制速覽

機制關鍵字/API適用場景
synchronized對象鎖 / 類鎖簡單臨界區、方法級同步
ReentrantLocklock()/unlock()、tryLock()、Condition需可中斷、超時、公平鎖、多條件變量
volatile字段修飾符單變量可見性、禁止指令重排
Atomic*CAS 無鎖操作計數器、狀態標誌、累加器
ThreadLocal線程私有副本上下文傳遞、數據庫連接、SimpleDateFormat
CountDownLatchawait()/countDown()主線程等待多子線程完成
CyclicBarrierawait()多線程相互等待匯聚點
Semaphoreacquire()/release()資源池限流 (連接池、許可證)
CompletableFuturesupplyAsync/thenApply/thenCombine異步編排、組合、異常處理 (JDK 8+)

避坑清單 (必讀)

  1. 不要在構造函數中啟動線程 (this 逸出風險)。
  2. 不要用 String/基本類型包裝類作為鎖 (常量池導致全局共享)。
  3. synchronized 塊內避免調用耗時 IO/睡眠 (持鎖時間過長)。
  4. 線程池提交任務捕獲異常:future.get() 或 重寫 afterExecute 記錄異常,否則異常吞沒無感知。
  5. 關閉線程池雙步驟:shutdown() 拒絕新任務 → awaitTermination() 等待執行中任務完成。
  6. ThreadLocal 使用完必須 remove(),防止線程池線程復用導致內存洩漏/數據串聯。

總結

Java 多線程核心在於「任務提交交給線程池、共享數據用同步手段保護、異步編排用 CompletableFuture」。掌握 Runnable + ThreadPoolExecutor + synchronized/ReentrantLock + Atomic/ThreadLocal 基礎組件,並牢記避坑清單,即可應對 90% 並發編程場景。進階方向:JUC 源碼剖析、JMM 內存模型、鎖優化 (偏向/輕量/重量)、非阻塞算法、虛擬線程。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved