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

Java 多線程入門筆記 (一):建立線程三種方式、生命週期、start vs run

     編輯:Java 相關知識

前言

多線程是 Java 核心競爭力之一。本文系統整理建立線程三種方式、Thread/Runnable/Callable 差異、線程生命週期狀態轉換、start() vs run() 關鍵區別,配合可執行範例程式碼。

一、建立線程三種方式

方式 1:繼承 Thread 類


class MyThread extends Thread {
    private int tickets;
    public MyThread(int tickets) { this.tickets = tickets; }
    @Override
    public void run() {
        for (; tickets > 0; tickets--) {
            System.out.println("當前線程:" + getName() + " 賣出第 " + tickets + " 張票");
            if (tickets == 1) System.out.println("票賣完,線程:" + getName());
        }
    }
}

// 使用
new MyThread(100).start();
new MyThread(100).start(); // 兩個線程各自賣 100 張 (不同任務)
  • 步驟:繼承 Thread → 重寫 run() → new 實例 → start()
  • 各線程執行獨立任務
  • 取得當前線程:getName() / this

方式 2:實作 Runnable 介面


class MyTask implements Runnable {
    private int tickets;
    public MyTask(int tickets) { this.tickets = tickets; }
    @Override
    public void run() {
        for (; tickets > 0; tickets--) {
            System.out.println("當前線程:" + Thread.currentThread() + " 賣出第 " + tickets + " 張票");
        }
    }
}

// 使用
MyTask task = new MyTask(100); // 單一任務實例
new Thread(task, "線程A").start();
new Thread(task, "線程B").start(); // 兩線程共享同一任務 (賣同 100 張票)
  • 步驟:實作 Runnable → 重寫 run() → 建立任務實例 → new Thread(task).start()
  • 多線程可共享同一任務實例 (協同賣票)
  • 取得當前線程:Thread.currentThread()
  • Java 8+ @FunctionalInterface 支援 Lambda:new Thread(() -> {...}).start()

方式 3:實作 Callable + FutureTask


class MyCallable implements Callable {
    private int tickets;
    public MyCallable(int tickets) { this.tickets = tickets; }
    @Override
    public String call() {
        for (; tickets > 0; tickets--) {
            System.out.println("當前線程:" + Thread.currentThread() + " 賣出第 " + tickets + " 張票");
        }
        return tickets == 0 ? "所有票賣完" : "票未賣完";
    }
}

// 使用
Callable callable = new MyCallable(100);
FutureTask future = new FutureTask<>(callable); // 實作 Runnable + Future
new Thread(future, "線程A").start();
new Thread(future, "線程B").start();

try {
    String result = future.get(); // 阻塞等待結果
    System.out.println("任務結果:" + result);
} catch (Exception e) { e.printStackTrace(); }
  • call() 有返回值、可拋受檢異常
  • FutureTask 同時實作 Runnable、Future
  • future.get() 阻塞取得結果,get(timeout, unit) 可設超時
  • Java 8+ Lambda:Callable c = () -> "result";

三種方式比較總結

維度ThreadRunnableCallable
繼承其他類不可 (單繼承)可可
取得當前線程this / getName()Thread.currentThread()Thread.currentThread()
共享任務不可可可
返回值無無有 (泛型)
拋異常無無可拋受檢異常
直接作 Target是 (本身是 Thread)是否 (需 FutureTask 包裝)

二、線程生命週期 (6 大狀態)

線程狀態轉換圖

  1. 新建:new Thread(),僅是普通物件
  2. 就緒:start() 後,等待 CPU 調度
  3. 執行:獲得 CPU,執行 run() 內容
  4. 阻塞:
    • sleep()、wait()
    • 阻塞式 IO
    • 等待同步鎖
    • suspend() (不建議,易死鎖)
  5. 等待:wait() 釋放鎖進入等待集
  6. 終止:
    • run() 正常結束
    • 未捕獲異常/錯誤
    • stop() (不建議,不安全)

狀態轉換關鍵點

  • 就緒 ↔ 執行:由 JVM 調度器決定
  • 執行 → 阻塞:呼叫阻塞方法
  • 阻塞 → 就緒:睡眠結束、IO 就緒、獲得鎖、被 notify
  • isAlive():新建/終止 回傳 false,其他 true

三、start() vs run() 關鍵區別

項目start()run()
作用啟動新線程,由 JVM 呼叫 run()普通方法呼叫,當前線程執行
線程狀態新建 → 就緒 → 執行狀態不變 (仍為新建)
可重複呼叫否 (拋 IllegalThreadStateException)可 (普通方法)
呼叫後能否 start否 (狀態已變)否 (run() 執行後狀態非新建)

鐵律

永遠不要直接呼叫 run()!必須用 start() 啟動線程。

總結

  • 三種建立方式:Thread 簡單、Runnable 靈活共享、Callable 有返回值
  • 生命週期 6 狀態轉換掌握調試關鍵
  • start() 啟動線程,run() 只是方法 —— 這是面試必考、實戰必錯的核心區別
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved