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

Java 多線程程式設計深度解析:從入門到核心原理

     編輯:Java 相關知識

多線程是實現程式並發執行的核心機制,允許單一程式中同時運行多個指令流,每個指令流稱為一個線程,彼此獨立調度。本文將系統剖析 Java 多線程的核心概念、實現方式、狀態模型、同步機制與進階特性。

一、理解多線程本質

線程被稱為輕量級進程,擁有獨立執行控制權,由作業系統調度。關鍵差異在於:線程無獨立存儲空間,而是與所屬進程中其他線程共享堆內存與方法區,這使得線程間通訊遠比進程間通訊(IPC)簡單高效。

多線程執行邏輯上「同時」,物理上取決於 CPU 核心數。單核 CPU 透過時間片輪轉實現併發,多核則可真正並行。開發者只需按並發模型設計,無需關心底層調度細節。

與單線程最大區別:多線程代碼執行順序不確定(亂序執行),引發線程調度、數據競態、同步互斥等核心挑戰。

二、Java 實現多線程的兩大路徑

Java 透過 java.lang.Thread 類支援多線程,核心在於指定線程執行代碼(run() 方法)。兩種實現方式:

1. 繼承 Thread 類

public class MyThread extends Thread {
    private int number;
    public MyThread(int num) { this.number = num; }
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("線程 " + number + ": 計數 " + i);
        }
    }
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) new MyThread(i).start();
    }
}

優點:直觀簡單。缺點:Java 單繼承限制,若類已繼承其他父類(如 Applet),無法再繼承 Thread。

2. 實現 Runnable 接口(推薦)

public class MyRunnable implements Runnable {
    private int number;
    public MyRunnable(int num) { this.number = num; }
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("線程 " + number + ": 計數 " + i);
        }
    }
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) 
            new Thread(new MyRunnable(i)).start();
    }
}

優點:解耦任務與執行機制,支援同一任務多線程並發,利於資源共享與封裝。缺點:需額外創建 Thread 實例,若需不同任務仍需多類實現。

最佳實踐:優先使用 Runnable 或 Callable + 線程池(ExecutorService),配合 Lambda 表達式簡化代碼。

三、線程四大生命週期狀態

  1. 新建:new Thread() 創建,未調用 start()。
  2. 可執行:調用 start() 後,等待 CPU 時間片,包含就緒與運行中。
  3. 阻塞:等待鎖、I/O、睡眠、等待通知等,放棄 CPU,不佔用時間片。
  4. 死亡:run() 正常返回、拋出未捕獲異常、調用 stop()/destroy()(已棄用,不安全)。

四、線程優先級與調度

優先級範圍 1(MIN)~ 10(MAX),預設 5(NORM)。高優先級線程獲取 CPU 機率較大,但非絕對佔有。透過 getPriority()/setPriority() 存取。注意:優先級不應作為程式正確性依賴,僅作優化提示。

五、線程同步:解決共享數據競態

多線程共享堆內存導致訪問衝突。Java 提供 synchronized 關鍵字實現互斥鎖:

1. synchronized 方法

public synchronized void accessVal(int newVal) { ... }

實例方法鎖住 this,靜態方法鎖住 Class 對象。同一時刻僅一線程可執行該實例/類的所有同步方法。

2. synchronized 代碼塊(粒度更細)

synchronized(lockObject) {
    // 臨界區代碼
}

可指定任意對象為鎖,靈活控制同步範圍,避免大方法同步導致效率低下(如鎖住 run() 會阻塞同類其他同步方法)。

六、線程阻塞與協作機制

同步解決「互斥」,阻塞機制解決「協作」(資源就緒通知)。

核心方法對比

方法所屬類釋放鎖喚醒方式適用場景
sleep(ms)Thread否時間到期定時輪詢、延遲執行
suspend()/resume()Thread否調用 resume()已棄用,易死鎖
yield()Thread否調度器重新分配主動讓出 CPU,同優先級輪轉
wait()/notify()Object是調用 notify()/notifyAll()生產者消費者、條件等待

wait/notify 核心規則

  • 必須在 synchronized 方法/塊中調用,否則拋 IllegalMonitorStateException。
  • 調用對象的鎖必須為當前線程持有。
  • wait() 釋放鎖並進入等待集;notify() 隨機喚醒一線程,notifyAll() 喚醒所有。
  • 喚醒後需重新獲取鎖才能繼續執行。

此機制類比作業系統 PV 原語,可構建信號量、管程等高級同步構件。

七、守護線程:後台服務者

非核心線程,JVM 僅存活非守護線程。當所有用戶線程結束,JVM 退出,守護線程被強制終止(不執行 finally、不釋放鎖)。常用於 GC、JIT 編譯、監控等後台服務。透過 setDaemon(true) 設置,必須在 start() 前調用。

八、線程組:批量管理與安全隔離

ThreadGroup 樹狀結構管理線程集合,支援批量設置優先級、中斷、守護屬性。亦作為安全邊界,不同組可應用差異化安全策略。現代開發較少直接使用,多由線程池、框架間接管理。

九、總結與選型建議

多線程核心在於「多代碼塊併發、亂序執行」。何時使用?

  • 無併發需求 → 單線程循環即可,簡單高效。
  • 有併發但無亂序依賴 → 線程池提交任務,避免手動管理複雜度。
  • 真正需要併發協作、共享狀態、異步處理 → 引入多線程,善用 java.util.concurrent 高級組件(鎖、條件、併發集合、Future、CompletableFuture)。

掌握多線程非僅是 API 熟悉,更是對併發模型、內存模型(JMM)、鎖優化、無鎖算法的深度理解。

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