CPU 進入多核時代,單執行緒程式效能不再自動提升,甚至因降頻而下降。並行程式若調優不當,反而比串行更慢。阿姆達爾定律告訴我們:即使 90% 程式碼可並行,10% 串行部分也會將 16 核加速比限制在 ~6 倍。本文提供系統性調優步驟與工具,助你逼近理論極限。

最常見原因是粗粒度鎖濫用。我們被教導「為了執行緒安全加鎖」,但鎖意味著序列化:同一時間只有一個執行緒進入臨界區,其他核心閒置等待。
Performance Inspector 開源工具組件,提供:
jlmlitestart (計數)、jlmstart (計數+時間)、jlmstop、jlmdump
class LogServerBad {
private final List queue = new ArrayList<>();
public synchronized void log(String msg) { queue.add(msg); } // 全域鎖
public synchronized String take() { return queue.remove(0); }
}
結果:隨執行緒增加,吞吐量幾乎不增 (藍線)。
class LogServerGood {
private final BlockingQueue queue = new ConcurrentLinkedQueue<>();
private final ExecutorService writer = Executors.newSingleThreadExecutor();
public void log(String msg) { queue.offer(msg); } // 無鎖入隊
// 背景單執行緒批次寫入檔案
public void start() {
writer.submit(() -> {
while (running) {
List batch = new ArrayList<>();
queue.drainTo(batch, 100); // 批次取出
writeToFile(batch);
}
});
}
}
結果:吞吐量隨核心數近線性增長 (綠線)。

使用 Project KunMing 的 LockFreeQueue 替換 ConcurrentLinkedQueue,高併發下進一步領先。

java.util.concurrent.atomic 提供無鎖原子操作:
// 差:synchronized 計數器
public synchronized int nextId() { return id++; }
// 好:AtomicInteger
private final AtomicInteger id = new AtomicInteger(0);
public int nextId() { return id.getAndIncrement(); }
適用:計數器、序號生成器、旗標切換。volatile 僅保證可見性,不保證複合操作原子性。
避免頻繁建立/銷毀執行緒開銷,控制併發度:
| 工廠方法 | 適用場景 |
|---|---|
| newFixedThreadPool(n) | 固定併發數,長期運行任務 |
| newCachedThreadPool() | 大量短期任務,空閒 60 秒回收 |
| newSingleThreadExecutor() | 串行化任務,保證順序 |
| newScheduledThreadPool(n) | 定時/週期性任務 |
關鍵:使用 ExecutorService 而非手動管理 Thread。
拋棄 Collections.synchronizedXxx() (全域鎖),改用細粒度鎖或無鎖實作:
| 介面 | 並發實作 | 特點 |
|---|---|---|
| Map | ConcurrentHashMap | 分段鎖 (預設 16 段),支援 putIfAbsent 等原子操作 |
| Queue | ConcurrentLinkedQueue | 無鎖 CAS 算法,高吞吐 |
| Map | ConcurrentSkipListMap | 跳表實作,有序並發 |
| List/Set | CopyOnWriteArrayList/Set | 寫時複製,適合讀多寫少 |