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

Java 多線程核心全解析:從基礎到實戰

     編輯:Java 程式設計入門

什麼是線程?線程與進程的區別

線程是程序執行的最小單元,也是 CPU 調度的基本單位。進程則是操作系統進行資源分配和調度的最小單位。一個進程可以包含多個線程,這些線程共享進程的記憶體空間和資源(如檔案句柄、網路連接等),但各自擁有獨立的程序計數器、棧和局部變量。這種共享機制讓線程間通訊更高效,但也帶來了線程安全問題。

多線程的概念與設計動機

並行 vs 並發

  • 並行:同一時刻有多條線程在不同 CPU 核心上同時執行。
  • 並發:同一時間段內,通過 CPU 時間片輪轉,多條線程交替執行,宏觀上看起來像同時運行。

Java 多線程實現的是並發模型(單核環境下)。設計多線程的核心目的是提高資源利用率和響應速度。例如音樂播放器邊播放邊下載,伺服器同時處理多個客戶端請求。

多線程面臨的核心問題

  1. 線程安全:多線程訪問共享資源時,如何保證數據一致性?
  2. 線程調度:Java 採用搶佔式調度,線程優先級範圍 1~10(預設 5),高優先級線程獲得 CPU 時間片機會較大,但不保證絕對順序。

Java 實現多線程的兩種基本方式

1. 繼承 Thread 類

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int x = 0; x < 200; x++) {
            System.out.println(x);
        }
    }
}

// 啟動
public class Demo {
    public static void main(String[] args) {
        new MyThread().start();
        new MyThread().start();
    }
}

關鍵點:必須調用 start() 而非 run()。start() 會請求 JVM 開啟新線程,並自動調用 run();直接調用 run() 只是普通方法調用,不會開啟新線程。

2. 實現 Runnable 接口(推薦)

public class Task implements Runnable {
    @Override
    public void run() {
        // 任務邏輯
    }
}

// 啟動
Thread t = new Thread(new Task());
t.start();

優勢:避免單繼承限制,任務與線程控制解耦,方便線程池複用。Thread 本身也實現了 Runnable。

線程狀態控制常用方法

方法說明
sleep(long ms)讓當前線程休眠指定毫秒,釋放 CPU,不釋放鎖。需捕獲 InterruptedException。
join()等待該線程終止。常用於主線程等待子線程完成。
yield()禮讓 CPU,當前線程從「運行」轉為「就緒」,讓同優先級線程有機會執行,不保證一定切換。
interrupt()設置中斷標誌。若線程處於阻塞狀態(sleep/wait/join),會拋出 InterruptedException 並清除標誌;若正在運行,僅設置標誌,需自行檢查 isInterrupted() 退出。

優雅停止線程範例:使用 volatile boolean 標誌位。

public class ControlledThread extends Thread {
    private volatile boolean running = true;
    public void shutdown() { running = false; }
    @Override public void run() {
        while (running) { /* 執行任務 */ }
    }
}

wait()/notify() 屬於鎖(Object)方法,配合 synchronized 使用,詳見下文。

線程安全、死鎖與生產者-消費者模型

線程不安全的成因

多線程、共享資源、非原子操作(如 D-- 包含讀取、修改、寫回三步)。經典售票例子會出現重複票、負號票。

synchronized 關鍵字解決線程安全

  • 同步代碼塊:synchronized(lockObj) { ... },鎖對象可任意,但多線程必須共用同一把鎖。
  • 同步實例方法:鎖為 this。
  • 同步靜態方法:鎖為當前類的 Class 對象。
// 正確:共享同一把鎖
private final Object lock = new Object();
public void run() {
    synchronized (lock) {
        if (D > 0) { System.out.println(Thread.currentThread().getName() + "---" + (D--)); }
    }
}

死鎖

兩個或多個線程互相持有對方需要的鎖,導致永久等待。避免策略:固定加鎖順序、使用 tryLock 超時機制、減少鎖嵌套。

生產者-消費者模式(wait/notify 實現)

共享緩衝區(如 ArrayList)作為鎖。生產者滿則 wait(),消費者空則 wait(),操作完成後 notifyAll() 喚醒等待線程。

// 生產者
synchronized (buffer) {
    while (buffer.size() >= MAX) buffer.wait();
    buffer.add(item);
    buffer.notifyAll();
}

// 消費者
synchronized (buffer) {
    while (buffer.isEmpty()) buffer.wait();
    Item item = buffer.remove(0);
    buffer.notifyAll();
}

線程優化:線程池

頻繁創建/銷毀線程開銷大。線程池預先創建固定數量線程,任務提交到隊列,線程反覆取任務執行,實現「空間換時間」。

ExecutorService pool = Executors.newFixedThreadPool(10);
pool.submit(new Runnable() { public void run() { /* 任務 */ } });
pool.shutdown(); // 關閉線程池

生產環境建議使用 ThreadPoolExecutor 自定義核心參數(核心數、最大數、隊列類型、拒絕策略),避免 Executors 默認配置導致 OOM。

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