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

Java 多線程核心技術全景:從基礎到線程安全的完整實戰指南

     編輯:Java 綜合教學

Java 多線程核心技術全景

多線程是 Java 並發編程的基石。本文涵蓋進程與線程概念、JVM 啟動機制、兩大實現方式、線程生命週期、調度與控制、線程安全問題與同步機制、線程安全集合,並附完整售票案例演示。

一、核心概念釐清

術語定義
進程執行中程式,資源分配獨立單位,擁有獨立記憶體空間
線程進程內執行單元/路徑,CPU 調度基本單位,共享進程資源
並行邏輯上同時發生,多 CPU 真正同一時刻執行
並發物理上輪流佔用 CPU,單 CPU 透過時間片切換模擬同時

Java 採用搶佔式調度:優先級高者獲得 CPU 時間片機率大,同優先級隨機選擇。

二、JVM 與主線程

  • java 命令啟動 JVM 進程,自動啟動主線程執行 main(),同時啟動GC 線程等,故 JVM 本身即多線程。

三、實現多線程兩大方案

方案 1:繼承 Thread 類

class MyThread extends Thread {
    @Override public void run() {
        for (int i = 0; i < 200; i++) System.out.println(getName() + ":" + i);
    }
}
public class Demo {
    public static void main(String[] args) {
        new MyThread().start(); // 必須呼叫 start(),不可直接呼叫 run()
    }
}

start() vs run():start() 啟動新線程並由 JVM 呼叫 run();直接呼叫 run() 視同普通方法,單線程執行。

方案 2:實作 Runnable 介面(推薦)

class MyTask implements Runnable {
    @Override public void run() {
        for (int i = 0; i < 100; i++) System.out.println(Thread.currentThread().getName() + ":" + i);
    }
}
public class Demo {
    public static void main(String[] args) {
        MyTask task = new MyTask();
        new Thread(task, "Thread-A").start();
        new Thread(task, "Thread-B").start(); // 同一任務物件,資料共享
    }
}

優勢:避免單繼承限制;任務與線程分離,適合多線程賣同一資源場景。

四、線程常用控制 API

方法作用關鍵點
sleep(ms)線程休眠,釋放 CPU,不釋放鎖static,拋 InterruptedException
join()等待該線程終止常用於主線程等待子線程
yield()禮讓 CPU,重新參與搶佔static,不保證切換成功
setDaemon(true)設為守護線程必須在 start() 前呼叫;JVM 僅剩守護線程時退出
interrupt()中斷線程(推薦)打斷阻塞狀態,拋 InterruptedException;stop() 已棄用

五、線程生命週期

線程生命週期圖

  • NEW → RUNNABLE(start) → RUNNING(獲取 CPU) ↔ BLOCKED/WAITING/TIMED_WAITING(阻塞/等待/超時等待) → TERMINATED(run 結束或異常)。

六、線程安全問題與同步機制

6.1 問題根源(三要素同時滿足)

  1. 多線程環境
  2. 共享資料
  3. 多條語句操作共享資料(非原子操作)

6.2 售票案例:從不安全到安全

// 不安全版:重複賣票、負票數
class SellTicket implements Runnable {
    private int tickets = 100;
    public void run() {
        while (true) {
            if (tickets > 0) {
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                System.out.println(Thread.currentThread().getName() + "賣第" + tickets-- + "張");
            }
        }
    }
}

6.3 同步代碼塊

private Object lock = new Object();
public void run() {
    while (true) {
        synchronized (lock) { // 任意對象作鎖,多線程必須共用同一把鎖
            if (tickets > 0) {
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                System.out.println(Thread.currentThread().getName() + "賣第" + tickets-- + "張");
            }
        }
    }
}

6.4 同步方法與靜態同步方法

  • synchronized void sell():鎖為 this。
  • static synchronized void sell():鎖為 ClassName.class(類字節碼物件)。

6.5 同步優缺點

  • 優點:解決線程安全。
  • 缺點:鎖檢查開銷大,高併發下降低吞吐量。

七、常見線程安全集合

傳統安全類現代推薦做法
Vector、Hashtable、StringBufferCollections.synchronizedList(new ArrayList<>())、ConcurrentHashMap、StringBuilder(單線程)

原則:優先用無鎖/低鎖集合(java.util.concurrent 套件),必要時再手動同步。

八、優先級與守護線程實戰

// 優先級 1-10,預設 5
t1.setPriority(Thread.MAX_PRIORITY); // 10
t2.setPriority(Thread.MIN_PRIORITY); // 1

// 守護線程:背景服務(如 GC、日誌)
daemonThread.setDaemon(true); // 必須 start() 前
daemonThread.start();

總結

  1. 掌握 Thread/Runnable 兩種啟動方式,理解 start() 與 run() 差異。
  2. 熟練運用 sleep/join/yield/interrupt/daemon 控制線程行為。
  3. 識別線程安全三要素,靈活運用 synchronized(代碼塊/方法/靜態方法)解決競態條件。
  4. 實務上優先使用 java.util.concurrent 高階組件(ReentrantLock、CountDownLatch、ThreadPoolExecutor 等)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved