許多開發者以為「我不 new Thread,就沒有多執行緒」。實則不然,Java 執行緒從框架、容器、工具類悄悄滲入應用程式。本文盤點五大隱性執行緒來源,解析其運作機制與同步風險,並給出防禦性程式設計建議。
Frame、JFrame、JComponent 即啟動。actionPerformed、mouseClicked 等)在 EDT 執行。SwingWorker、ExecutorService),完成後用 SwingUtilities.invokeLater 更新 UI。System.exit() 或關閉所有視窗才結束。new Timer() 內部建立單一「Timer-ScheduledExecutorService(多執行緒、可控併發)。ThreadLocal、請求屬性、或同步區塊/並發集合。UnicastRemoteObject 會啟動 Socket 監聽執行緒 + 多工處理執行緒池。| 場景 | 風險 | 防禦措施 |
|---|---|---|
| EDT 讀取共享資料 | 資料競爭、看見中間狀態 | 用 volatile/Atomic/鎖保護;或複製快照傳給 EDT |
| TimerTask 寫入共享集合 | ConcurrentModificationException | 用 ConcurrentHashMap/CopyOnWriteArrayList |
| Servlet 實例欄位計數器 | 計數遺漏/重複 | 改用 AtomicLong 或 ThreadLocal |
| RMI 回呼客戶端 Callback | 客戶端非執行緒安全 | 客戶端同步處理或佇列串行化 |
ExecutorService、CompletableFuture、ConcurrentHashMap、BlockingQueue,避免手動 synchronized/wait。Runtime.getRuntime().addShutdownHook 正確關閉執行緒池、連線池,避免資源洩漏。執行緒無處不在,不是負擔,而是 Java 平台能力的體現。識別隱性執行緒來源、理解其生命週期與同步邊界,是寫出健壯併發應用的前提。下次除錯詭異 Bug 時,請先問自己:「這裡到底在哪條執行緒跑?」