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

Java 並發進階(一):Lock 鎖優勢、Executor 框架、線程池七大參數、Fork/Join 工作竊取原理

     編輯:Java 綜合教學

Java 並發進階(一):Lock 鎖優勢、Executor 框架、線程池七大參數、Fork/Join 工作竊取原理

java.util.concurrent (JUC) 是 Java 並發編程的基石。本文系統講解顯式 Lock 鎖、Executor 執行者體系、線程池核心參數與拒絕策略、Fork/Join 分治框架四大支柱,附帶源碼級原理分析與生產配置建議。

一、顯式 Lock 鎖:超越 synchronized 的靈活性

核心接口:java.util.concurrent.locks.Lock


Lock lock = new ReentrantLock();
if (lock.tryLock()) {           // 嘗試非阻塞獲取
    try {
        // 臨界區
    } finally {
        lock.unlock();          // 必須在 finally 中釋放
    }
} else {
    // 獲取失敗,執行備選邏輯
}

Lock vs synchronized 對比

Condition 精準喚醒示例


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(); }

// 消費者
lock.lock();
try {
    while (queue.isEmpty()) notEmpty.await();
    Item item = queue.poll();
    notFull.signal();
    return item;
} finally { lock.unlock(); }

二、Executor 執行者體系:解耦任務提交與執行

三大核心接口

特性synchronizedLock (ReentrantLock)
獲取方式隱式(語法糖)顯式 API
可中斷不可中斷lockInterruptibly() 可響應中斷
超時獲取不支持tryLock(timeout, unit) 支持超時
公平性非公平可選公平/非公平(構造傳 true)
條件變量wait/notify/notifyAll多個 Condition 支持精準喚醒
死鎖預防困難tryLock 失敗可回退,避免死等
性能 (低爭用)JDK6+ 優化後極快略慢(CAS+自旋)
性能 (高爭用)明顯下降優於 synchronized

工廠方法創建線程池


// 固定大小線程池(核心=最大,無閒置超時,無界隊列)
ExecutorService fixed = Executors.newFixedThreadPool(n);

// 可緩存線程池(核心0,最大Integer.MAX_VALUE,60s閒置回收,同步隊列)
ExecutorService cached = Executors.newCachedThreadPool();

// 單線程池(串行執行,保證順序)
ExecutorService single = Executors.newSingleThreadExecutor();

// 定時任務線程池
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(n);

三、ThreadPoolExecutor 七大參數全解析(阿里巴巴開發手冊強制要求)


public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
接口繼承關係核心方法職責
Executor頂層execute(Runnable)啟動任務,替代 new Thread(r).start()
ExecutorServiceextends Executorsubmit(Callable), shutdown(), invokeAll生命周期管理、Future 返回值、批量提交
ScheduledExecutorServiceextends ExecutorServicescheduleAtFixedRate, scheduleWithFixedDelay定時/周期性任務

四大標準拒絕策略

參數含義配置建議
corePoolSize核心線程數(常駐)CPU 密集:CPU 核心數 +1;IO 密集:2*CPU 核心數
maximumPoolSize最大線程數根據業務峰值壓測確定,防止 OOM
keepAliveTime非核心線程閒置存活時間60s-300s,避免頻繁創建銷燬
unit時間單位TimeUnit.SECONDS
workQueue任務隊列必須有界:ArrayBlockingQueue(有界) 或 LinkedBlockingQueue(指定容量)
threadFactory線程工廠命名 biz-xxx-%d,便於排查;可用 Guava ThreadFactoryBuilder
handler拒絕策略見下表

自定義拒絕策略:記錄日志 + 降級


public class LogAndFallbackRejectedHandler implements RejectedExecutionHandler {
    private static final Logger log = LoggerFactory.getLogger(LogAndFallbackRejectedHandler.class);
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        log.warn("線程池拒絕任務: {}, 當前隊列: {}, 活躍線程: {}", 
                 r.getClass().getSimpleName(), executor.getQueue().size(), executor.getActiveCount());
        // 降級邏輯:寫入磁盤隊列、發送告警、返回默認值等
        fallback(r);
    }
}

四、Fork/Join 框架:分治遞歸任務的並行利器

核心類

  • ForkJoinPool:專用線程池,實現工作竊取算法。
  • ForkJoinTask:任務基類,子類 RecursiveTask (有返回值)、RecursiveAction (無返回值)。

工作竊取原理

  1. 每個工作線程維護一個雙端隊列 (Deque)。
  2. 任務分解產生的子任務 push 到隊頭。
  3. 線程處理完自身任務,從其他線程隊尾竊取任務執行。
  4. 減少全局隊列爭用,實現負載均衡,充分利用多核。

使用範例:並行求和


static class SumTask extends RecursiveTask {
    private final long[] arr;
    private final int lo, hi;
    private static final int THRESHOLD = 10_000;

    SumTask(long[] arr, int lo, int hi) { this.arr = arr; this.lo = lo; this.hi = hi; }

    @Override protected Long compute() {
        if (hi - lo <= THRESHOLD) {
            long sum = 0;
            for (int i = lo; i < hi; i++) sum += arr[i];
            return sum;
        }
        int mid = (lo + hi) >>> 1;
        SumTask left = new SumTask(arr, lo, mid);
        SumTask right = new SumTask(arr, mid, hi);
        left.fork();              // 異步執行左半部分
        long rightAns = right.compute(); // 當前線程執行右半部分
        return rightAns + left.join();   // 合併結果
    }
}

// 執行
ForkJoinPool pool = new ForkJoinPool();
long sum = pool.invoke(new SumTask(arr, 0, arr.length));

JDK 內置 Fork/Join 應用

  • Arrays.parallelSort():大數組並行排序,多核下比串行快 2-4 倍。
  • Stream.parallel():並行流底層即 ForkJoinPool.commonPool()。
  • CompletableFuture 異步編排亦複用公共池。

生產配置清單

  1. ✅ 所有線程池顯式命名(ThreadFactory),禁用 Executors 默認工廠。
  2. ✅ 隊列必須有界,防止內存飛升 OOM。
  3. ✅ 核心參數外部化配置(Nacos/Apollo),支持動態調整無需重啟。
  4. ✅ 關鍵業務線程池隔離,避免非關鍵任務佔用資源導致核心業務超時。
  5. ✅ 監控指標:activeCount, queueSize, completedTaskCount, rejectCount 接入 Prometheus。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
策略行為適用場景
AbortPolicy (默認)拋 RejectedExecutionException關鍵業務,快速失敗,上層熔斷降級
CallerRunsPolicy調用者線程執行任務緩衝突發流量,利用調用者線程背壓
DiscardPolicy靜默丟棄非關鍵監控/日志,可容忍丟失
DiscardOldestPolicy丟棄隊列頭部最老任務,重試提交優先處理新請求,如實時行情推送