Runnable 更符合 OO:任務與執行分離,支援同一任務多線程執行 (資料共享)Thread.run() 源碼:若 target != null 則呼叫 target.run(),否則空實作run() 且傳入 Runnable,**子類 run() 生效**,Runnable 被忽略**不一定**。單核 CPU 下多線程因上下文切換反而降低效率。多線程下載「快」是因為佔用更多伺服器頻寬,而非本機 CPU 變快。
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() { System.out.println("執行任務"); }
}, 1000, 2000); // 延遲 1s,每 2s 執行
// 固定速率
timer.scheduleAtFixedRate(task, date, period);
缺點:單執行緒串行執行、異常導致後續任務停止、無彈性排程。生產環境建議用 Quartz** 或 **ScheduledExecutorService**。
// 錯誤示範:兩個 synchronized 但鎖不同
public void print1() { synchronized(MyClass.class) { ... } }
public void print2() { synchronized(this) { ... } } // 無互斥效果
靜態方法鎖 = Class 物件,實例方法鎖 = this。
而非寫在線程類中,這樣資源類天然線程安全,任意線程均可安全調用。
class Output {
private boolean flag = true; // true: 主線程, false: 子線程
public synchronized void sub(int i) {
while (!flag) { wait(); } // while 防偽喚醒
for (int j=0; j<10; j++) System.out.println(i + "子線程" + j);
flag = true; notify();
}
public synchronized void main(int i) {
while (flag) { wait(); }
for (int j=0; j<100; j++) System.out.println(i + "主線程" + j);
flag = false; notify();
}
}
同一線程內多模組 (A/B) 需共享數據,但不同線程間數據隔離 (如事務上下文、資料庫連線)。
static Map datas = new HashMap<>();
// 存: datas.put(Thread.currentThread(), value);
// 取: datas.get(Thread.currentThread());
Thread 內部持有 ThreadLocalMapThreadLocal 作為 Key,值存入當前線程的 Mapget()/set() 自動綁定當前線程// 1. 定義 (通常 static)
static ThreadLocal connLocal = new ThreadLocal<>();
// 2. 綁定 (如 Filter/Interceptor 開啟事務時)
connLocal.set(dataSource.getConnection());
// 3. 任意處取用 (同一線程)
Connection conn = connLocal.get();
// 4. 移除 (防洩漏,如請求結束)
connLocal.remove();
父線程建立子線程時自動複製值,適用於追蹤 ID 透傳。
ThreadLocalMap Key 為弱引用,Value 強引用ThreadLocal 實例回收但線程存活 (如線程池),Value 無法 GCremove()**