線程是輕量級進程,擁有獨立執行棧與程序計數器,但共享進程堆內存。多線程實現邏輯上的「並發」,單 CPU 通過時間片輪轉模擬同時運行。最大挑戰在於共享數據的競態條件與線程協作。
public class MyThread extends Thread {
private final int id;
public MyThread(int id) { this.id = id; }
@Override public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("線程 " + id + " 計數:" + i);
}
}
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) new MyThread(i).start();
}
}
缺點:Java 單繼承限制,若已繼承 Applet 等類則無法使用。
public class MyTask implements Runnable {
private final int id;
public MyTask(int id) { this.id = id; }
@Override public void run() { /* 同上 */ }
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) new Thread(new MyTask(i)).start();
}
}
優勢:職責分離,任務邏輯與線程控制解耦,支援線程池提交,便於單元測試。
new Thread(),未調用 start()。sleep()、wait() 等,不佔用 CPU。run() 正常返回或拋出未捕獲異常。棄用警告:stop()、suspend()、destroy() 皆不安全,會導致鎖釋放異常或數據不一致。
優先級 1~10(默認 5),高優先級獲取 CPU 機率大但非絕對。調度策略由 JVM 與作業系統共同決定,不可依賴優先級實現業務邏輯順序。
public synchronized void transfer(Account from, Account to, int amount) { ... }
鎖住 this 實例,同一實例的所有同步方法互斥。靜態同步方法鎖住 Class 對象。
public void transfer(Account from, Account to, int amount) {
synchronized (from) {
synchronized (to) { // 注意固定加鎖順序防死鎖
// 核心轉賬邏輯
}
}
}
僅鎖住關鍵區段,減少鎖持有時間,提升併發吞吐。
每個對象頭包含 Mark Word,指向 Monitor 對象。線程進入同步區需獲取 Monitor 所有權,失敗則進入 EntryList 等待;wait() 釋放鎖進入 WaitSet;notify() 喚醒移回 EntryList 重新競爭。
java.util.concurrent 高級組件(ReentrantLock、CountDownLatch、ConcurrentHashMap 等)。ThreadLocal)隔離狀態,避免同步。