Java 讓多線程簡單到「幾乎自然」,但仍需掌握核心概念:main() 本身即線程,僅在需要額外並行時建立新線程。本文詳細對比 Thread 繼承與 Runnable 實現兩大模式,並引入 synchronized 保護共享資料。
Thread 為具體類別,非抽象類run() 封裝任務邏輯start() 啟動(絕不直接呼叫 run())import java.util.*;
class TimePrinter extends Thread {
int pauseTime; String name;
public TimePrinter(int x, String n) { pauseTime = x; name = n; }
public void run() {
while (true) {
try {
System.out.println(name + ":" + new Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
} catch (Exception e) { System.out.println(e); }
}
}
static public void main(String args[]) {
TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
tp1.start();
TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
tp2.start();
// main() 線程繼續執行,共三線程並行
}
}
run(),不強加類別繼承體系Thread 時傳入 Runnable 實例import java.util.*;
class TimePrinter implements Runnable {
int pauseTime; String name;
public TimePrinter(int x, String n) { pauseTime = x; name = n; }
public void run() { /* 同前 */ }
static public void main(String args[]) {
Thread t1 = new Thread(new TimePrinter(1000, "Fast Guy"));
t1.start();
Thread t2 = new Thread(new TimePrinter(3000, "Slow Guy"));
t2.start();
}
}
RunnableRunnableThread 繼承亦可接受public class Account {
String holderName; float amount;
public Account(String name, float amt) { holderName = name; amount = amt; }
public void deposit(float amt) { amount += amt; }
public void withdraw(float amt) { amount -= amt; }
public float checkBalance() { return amount; }
}
聯合帳戶雙方同時在不同 ATM 操作,deposit/withdraw 交錯執行導致更新遺失。
public class Account {
String holderName; float amount;
public Account(String name, float amt) { holderName = name; amount = amt; }
public synchronized void deposit(float amt) { amount += amt; }
public synchronized void withdraw(float amt) { amount -= amt; }
public float checkBalance() { return amount; } // 唯讀無需同步
}
synchronized 方法需獲取鎖才能執行,其他同步方法阻塞checkBalance() 未同步:不阻塞寫入,寫入不阻塞讀取(可能讀到舊值,視業務容忍度)synchronized(this) { ... } 區塊ReadWriteLock (JDK 1.5+)