Java 多線程基石:建立方式、生命週期、同步機制與常見陷阱
一、線程建立的兩種方式
| 方式 | 代碼範例 | 優缺點 |
| 繼承 Thread | class MyThread extends Thread { public void run() {...} } | 單繼承限制,線程與任務強耦合,復用性差 |
| 實作 Runnable | class MyTask implements Runnable { public void run() {...} } new Thread(new MyTask()).start(); | 分離任務與執行,支援匿名內部類/Lambda,推薦使用 |
二、關鍵 API
Thread.currentThread():獲取當前線程
getId()/getName()/getPriority():屬性查詢
setPriority(int):設置優先級(1-10),僅為調度提示
sleep(ms):靜態方法,釋放 CPU 進入 TIMED_WAITING
yield():放棄當前時間片,回到 RUNNABLE
join():等待目標線程終止
setDaemon(true):標記為守護線程(需在 start 前調用),JVM 僅剩守護線程時退出
三、同步機制
1. synchronized 關鍵字
- 修飾實例方法:鎖
this
- 修飾靜態方法:鎖
Class 物件
- 修飾代碼塊:
synchronized(lockObj) { ... },縮小鎖範圍提升並發
2. 互斥與死鎖
- 同一物件多個 synchronized 區塊互斥
- 死鎖條件:互斥、持有並等待、不可搶佔、循環等待
四、經典面試陷阱
// 錯誤:直接調用 run() 不會啟動新線程
new MyThread().run(); // 主線程同步執行
// 正確
new MyThread().start(); // 納入調度器,稍後由 JVM 呼叫 run()
五、最佳實踐建議
- 優先使用
Runnable + 線程池 (ExecutorService)
- 鎖粒度越小越好,但避免過度優化
- 使用
java.util.concurrent 高層工具(Lock、CountDownLatch、ConcurrentHashMap 等)
- 避免在同步塊中調用耗時操作(I/O、sleep)
- 線程命名規範:
Thread.currentThread().setName("Order-Processor-1")