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

Java 多線程程式設計機制深度解析:從線程生命週期到同步控制

     編輯:Java 相關知識

前言

多線程是 Java 語言的核心特性之一,它允許程式在同一時間內並行執行多個任務,極大地提升了應用程式的響應速度與資源利用率。本文將系統性地介紹 Java 多線程的基本概念、線程生命週期、優先級調度、實現方式以及線程同步機制,並輔以代碼範例幫助開發者深入理解。

核心概念:程式、進程與線程

在探討多線程之前,需釐清三個易混淆的概念:

  • 程式:靜態的代碼集合,如編譯後的 .class 檔案。
  • 進程:程式的一次動態執行過程,擁有獨立的記憶體空間,包含從代碼載入到執行結束的完整生命週期。
  • 線程:進程內部的執行單元,比進程更輕量。一個進程可孕育多個線程,共享進程的記憶體與資源,各自擁有獨立的程式計數器、堆疊與局部變數。

以 QQ 客戶端為例:客戶端本身是「程式」;登入 QQ 啟動一個「進程」;與好友聊天發送訊息則對應進程中的一條「線程」。

線程的生命週期與五大狀態

Java 使用 java.lang.Thread 類及其子類對象來代表線程。一個線程從誕生到消亡,會經歷以下五種狀態:

1. 新建

當使用 new Thread() 或繼承 Thread 類創建實例時,線程進入新建狀態。此時已分配記憶體與資源,但尚未啟動。

2. 就緒

調用 start() 方法後,線程進入就緒隊列,等待 CPU 排程。具備執行條件,一旦獲得 CPU 時間片即可進入運行狀態。

3. 運行

線程獲得 CPU 執行權,開始執行 run() 方法中的代碼邏輯。所有線程操作的核心代碼均應編寫在 run() 方法內。

4. 阻塞

運行中的線程因等待資源(如 I/O、鎖、Sleep)而暫時放棄 CPU,進入阻塞狀態。阻塞原因消除後,線程重新回到就緒隊列等待調度。

5. 死亡

run() 方法正常執行完畢,或因異常、stop() 強制終止,線程結束生命週期,不可再重新啟動。

線程優先級與調度

Java 線程採用搶佔式調度,優先級高的線程更容易獲得 CPU。優先級分三級:

  • MIN_PRIORITY = 1(低)
  • NORM_PRIORITY = 5(普通,主線程預設)
  • MAX_PRIORITY = 10(高)

可透過 setPriority(int) 修改,但最終調度仍取決於作業系統。

實現多線程的兩種途徑

方式一:繼承 Thread 類

class MyThread extends Thread {
    public void run() {
        // 線程執行邏輯
    }
}
// 使用
MyThread t = new MyThread();
t.start(); // 啟動線程,進入就緒狀態

方式二:實現 Runnable 介面(推薦)

class MyRunnable implements Runnable {
    public void run() {
        // 線程執行邏輯
    }
}
// 使用
Thread t = new Thread(new MyRunnable());
t.start();

Runnable 方式解耦了線程任務與線程控制,便於資源共享,且避免單繼承限制。

常用線程控制方法

方法說明
sleep(long ms)讓當前線程休眠指定毫秒,不釋放鎖
yield()讓出 CPU,重新參與調度
join()等待該線程終止
isAlive()判斷線程是否存活

線程同步:解決共享資源競爭

多線程同時存取共享資料時會發生線程安全問題。Java 提供 synchronized 關鍵字實現同步:

  • 同步方法:public synchronized void method() { ... }
  • 同步區塊:synchronized(obj) { ... }

同步機制確保同一時間只有一個線程能執行被保護的代碼區段,其他線程需等待鎖釋放。

經典範例:會計與出納共用帳本

public class BankDemo extends Applet implements Runnable {
    int money = 100;
    Thread accountant, cashier;
    TextArea log1, log2;

    public void init() {
        accountant = new Thread(this);
        cashier = new Thread(this);
        log1 = new TextArea(20, 8);
        log2 = new TextArea(20, 8);
        add(log1); add(log2);
    }

    public void start() {
        accountant.start();
        cashier.start();
    }

    // 同步方法:同一時間只允許一個線程存取
    public synchronized void access(int amount) {
        if (Thread.currentThread() == accountant) {
            for (int i = 0; i < 3; i++) {
                money += amount;
                try { Thread.sleep(1000); } catch (Exception e) {}
                log1.append("\n" + money);
            }
        } else if (Thread.currentThread() == cashier) {
            for (int i = 0; i < 2; i++) {
                money -= amount / 2;
                try { Thread.sleep(1000); } catch (Exception e) {}
                log2.append("\n" + money);
            }
        }
    }

    public void run() {
        if (Thread.currentThread() == accountant || Thread.currentThread() == cashier) {
            for (int i = 0; i < 3; i++) access(30);
        }
    }
}

線程通信:wait()、notify()、notifyAll()

當線程需等待某條件滿足時,可在同步區塊中調用 wait() 釋放鎖並進入等待池;條件滿足後,其他線程調用 notify()(喚醒單一線程)或 notifyAll()(喚醒所有等待線程)使其重新競爭鎖。

  • wait():線程等待,釋放鎖
  • notify():喚醒一個等待線程
  • notifyAll():喚醒所有等待線程

這三個方法屬於 Object 類,必須在同步上下文中調用,否則拋出 IllegalMonitorStateException。

總結

Java 多線程機制為並發程式設計提供了強大支撐。掌握線程生命週期、優先級調度、實現方式、同步與通信,是開發高效、穩定並發應用的基石。實務中應根據業務場景合理選擇同步粒度,避免過度同步導致效能下降,並善用 java.util.concurrent 套件中的高階工具(如 Lock、CountDownLatch、ThreadPoolExecutor)簡化開發。

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