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

Java 多線程實現三種方式深度解析:Thread/Runnable/Callable、五大狀態轉換圖

     編輯:Java 綜合教學

Java 多線程實現三種方式深度解析:Thread/Runnable/Callable、五大狀態轉換圖

多線程是 Java 並發編程的基石。本文系統講解:
① 線程與進程區別、五大狀態轉換
② 三種創建方式 (Thread/Runnable/Callable) 代碼對比
③ 為什麼推薦 Runnable、Callable 適用場景
④ 實戰中常見的睡眠/讓步/等待通知/同步阻塞細節

一、核心概念

  • 進程:資源分配基本單位,擁有獨立內存空間
  • 線程:CPU 調度基本單位,屬於某進程,共享進程內存/文件句柄,開銷極小
  • 多線程:單進程內多條線程並發執行,宏觀並行、微觀分時輪轉

二、線程五大狀態與轉換

┌─────────┐     start()      ┌─────────┐   CPU調度    ┌─────────┐
│  NEW    │ ────────────────► │ RUNNABLE │ ──────────► │ RUNNING │
└─────────┘                   └─────────┘              └────┬────┘
                                                             │
                    ┌───────────────────────────────────────┘
                    ▼
            ┌─────────────┐
            │  BLOCKED    │ ◄── sleep/wait/join/同步鎖/IO
            └──────┬──────┘
                   │ 喚醒/超時/獲取鎖
                   ▼
            ┌─────────────┐
            │ RUNNABLE    │ (回到就緒隊列)
            └─────────────┘
                   │
                   │ run() 結束 / 異常
                   ▼
            ┌─────────────┐
            │  TERMINATED │
            └─────────────┘

阻塞細分 (面試高頻)

方法釋放鎖喚醒方式進入狀態
sleep(ms)否時間到TIMED_WAITING
wait()是notify/notifyAll/超時WAITING/TIMED_WAITING
join()否目標線程結束WAITING
LockSupport.park()否unpark()WAITING
同步鎖否獲取鎖BLOCKED

三、三種創建方式代碼對比

1. 繼承 Thread

class MyThread extends Thread {
    @Override public void run() {
        for (int i=0; i<10; i++) 
            System.out.println(Thread.currentThread().getName()+" "+i);
    }
}
new MyThread().start();
new MyThread().start();

輸出:兩線程交替打印,隨機搶佔 CPU

2. 實現 Runnable (推薦)

class MyRunnable implements Runnable {
    @Override public void run() { /* 同邏輯 */ }
}
MyRunnable r = new MyRunnable();
new Thread(r).start(); // 線程1
new Thread(r).start(); // 線程2 共享同一 Runnable 實例 → 數據共享

優勢:邏輯與線程控制解耦、避免單繼承限制、天然支援數據共享

3. Callable + FutureTask (有返回值)

class MyCallable implements Callable<Integer> {
    @Override public Integer call() { return 1; }
}
FutureTask<Integer> task = new FutureTask<>(new MyCallable());
new Thread(task).start();
Integer result = task.get(); // 阻塞等待結果
System.out.println(result); // 1

適用:需獲取執行結果、拋出受檢異常的異步任務

四、Runnable vs Thread 選型決策表

維度Thread 繼承Runnable 實現
繼承限制單繼承,若已繼承其他類則不可用可多實現,無限制
數據共享需額外傳遞共享對象同一實例傳給多線程,天然共享
代碼復用邏輯綁定線程類,難復用邏輯獨立,可傳給線程池/CompletableFuture
推薦度⭐ (僅簡單練習)⭐⭐⭐⭐⭐ (生產首選)

五、實戰避坑指南

  1. start() vs run():直接調用 run() 只是普通方法調用,**不會開啟新線程**,必須調用 start()
  2. 線程命名:new Thread(r, "order-consumer-1"),日誌排查關鍵
  3. 異常處理:Runnable.run() 不拋受檢異常,需內部 try-catch 或用 Callable
  4. 停止線程:禁止用 stop()/suspend()/resume() (已棄用),改用 volatile boolean running 標誌位 + interrupt() 協作式停止
  5. 守護線程:setDaemon(true) 需在 start() 前設置,JVM 退出時不等待守護線程

現代最佳實踐:業務代碼**不直接 new Thread**,統一提交至業務隔離線程池 (自定義 ThreadPoolExecutor),配合 CompletableFuture 實現異步編排,框架層統一管理生命週期、監控、熔斷。

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