首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多執行緒核心總結:基礎概念、生命週期、三種實作方式與原理深度解析

     編輯:Java 相關知識

一、進程 vs 執行緒

維度進程執行緒
定義執行中程式的實例,資源分配基本單位程式執行流最小單位,CPU 調度基本單位
記憶體獨立位址空間共享進程記憶體(堆、方法區),私有棧、PC 計數器
建立/切換開銷大小(輕量級進程)
穩定性一個進程崩潰不影響其他一個執行緒崩潰可能導致整個進程退出
通訊方式IPC(管道、Socket、共享記憶體)共享變數、wait/notify、Lock、Queue 等

二、執行緒生命週期與五大狀態

NEW (新建) → RUNNABLE (就緒) ↔ RUNNING (執行)
                    ↑    ↓
              BLOCKED (阻塞) ← WAITING / TIMED_WAITING
                    ↓
              TERMINATED (終止)
  1. NEW:new Thread() 建立物件,未呼叫 start()。
  2. RUNNABLE:呼叫 start() 後,等待 CPU 排程。
  3. RUNNING:獲得 CPU 時間片,執行 run()。
  4. BLOCKED:
    • 同步阻塞:等待 synchronized 鎖。
    • 等待阻塞:wait()、join()、sleep()、I/O。
  5. TERMINATED:run() 正常結束或拋出未捕獲異常。

三、三種實作多執行緒方式

1. 繼承 Thread 類別

class MyThread extends Thread {
    private String name;
    public MyThread(String name) { this.name = name; }
    @Override public void run() {
        for (int i = 0; i < 10; i++) System.out.println(name + " i=" + i);
    }
}
public class Demo {
    public static void main(String[] args) {
        new MyThread("A").start();
        new MyThread("B").start();
        new MyThread("C").start();
    }
}

缺點:Java 單繼承限制,無法繼承其他業務類別。

2. 實作 Runnable 介面(推薦)

class MyTask implements Runnable {
    private String name;
    public MyTask(String name) { this.name = name; }
    @Override public void run() { /* 同前 */ }
}
public class Demo {
    public static void main(String[] args) {
        new Thread(new MyTask("A")).start();
        new Thread(new MyTask("B")).start();
        new Thread(new MyTask("C")).start();
    }
}

優點:避免單繼承限制,任務與執行緒控制分離,方便傳入執行緒池。

3. 實作 Callable + FutureTask(可獲取回傳值、拋出異常)

class MyTask implements Callable<String> {
    @Override public String call() throws Exception {
        // 模擬賣票
        for (int i = 10; i > 0; i--) System.out.println("剩餘票數:" + i);
        return "售罄";
    }
}
public class Demo {
    public static void main(String[] args) throws Exception {
        FutureTask<String> ft1 = new FutureTask<>(new MyTask());
        FutureTask<String> ft2 = new FutureTask<>(new MyTask());
        new Thread(ft1).start();
        new Thread(ft2).start();
        System.out.println("執行緒1結果:" + ft1.get()); // 阻塞等待結果
        System.out.println("執行緒2結果:" + ft2.get());
    }
}

關鍵點:FutureTask 實作 RunnableFuture → Runnable,可直接丟給 Thread;get() 會阻塞直到任務完成。

四、為什麼必須呼叫 start() 而非 run()?

  • start():原生方法,向 OS 申請新執行緒,完成後由 JVM 呼叫 run()。
  • run():單純方法呼叫,仍在主執行緒中循序執行,不具備多執行緒特性。
  • 原始碼中 start0() 為 native,交由 JVM 依平台實作(Windows/Linux 不同)。

五、常見誤區與最佳實踐

誤區正確做法
同一 Thread 物件呼叫兩次 start()會拋 IllegalThreadStateException,一個物件只能啟動一次。
在 run() 中直接操作 UI(Swing/JavaFX)需用 SwingUtilities.invokeLater / Platform.runLater 切回 UI 執行緒。
大量建立 Thread 物件使用 ExecutorService 執行緒池,控制併發數、重用執行緒。
共享變數未同步用 volatile、Atomic*、synchronized、Lock 保證可見性與原子性。

總結

掌握「進程/執行緒差異、五大狀態流轉、三種實作方式優劣、start() 底層原理」是 Java 併發編程的基石。實務上首選 Runnable + 線程池,需回傳值用 Callable + Future,複雜協作再引入 CompletableFuture、CountDownLatch、Semaphore 等高階工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved