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

Java 多線程核心:Runnable 與 Thread 深度解析及線程安全實戰

     編輯:Java 綜合教學

Runnable 與 Thread:核心區別與線程安全實戰

在 Java 多線程開發中,Runnable 接口與 Thread 類是兩種創建線程的基本方式,但它們在線程安全、代碼復用、架構設計上有本質區別。本文通過經典的「售票案例」深度剖析兩者差異。

一、基本概念對比

維度Runnable 接口Thread 類
本質函數式接口,僅定義 run() 方法類,實現了 Runnable,代表線程實體
創建線程實現接口 → 實例化對象 → 傳入 Thread 構造器 → start()繼承 Thread → 重寫 run() → 實例化 → start()
數據共享天然支持:同一 Runnable 實例可被多個 Thread 共享數據隔離:每個 Thread 子類實例擁有獨立數據副本
繼承限制無限制,可繼承其他類單繼承限制,已繼承 Thread 無法繼承其他業務類
線程安全共享數據需自行同步(synchronized / Lock)各實例數據獨立,無共享安全問題,但無法實現真正的「多線程賣同一張票」

二、售票案例代碼對比

1. 繼承 Thread 方式(每線程獨立 10 張票)

public class MyThread extends Thread {
    public int ticks = 10; // 每個實例擁有獨立 ticks
    boolean flag = true;
    public MyThread(String name) { this.setName(name); }
    @Override public void run() { while(flag) saleTick(); }
    public void saleTick() {
        if(ticks > 0) { ticks--; System.out.println(Thread.currentThread().getName() + ":" + ticks); }
        else flag = false;
    }
}

2. 實現 Runnable 方式(三線程共享 10 張票)

public class MyRunnable implements Runnable {
    public int ticks = 10; // 單一實例,數據共享
    boolean flag = true;
    @Override public void run() { while(flag) saleTick(); }
    public void saleTick() {
        if(ticks > 0) { ticks--; System.out.println(Thread.currentThread().getName() + ":" + ticks); }
        else flag = false;
    }
}

3. 測試類與運行結果

public class Test {
    public static void main(String[] args) {
        // Thread 方式:三個實例,各賣 10 張,共 30 張
        new MyThread("thread1").start();
        new MyThread("thread2").start();
        new MyThread("thread3").start();

        // Runnable 方式:一個實例,三個線程共享,共賣 10 張
        MyRunnable mr = new MyRunnable();
        new Thread(mr, "runnable1").start();
        new Thread(mr, "runnable2").start();
        new Thread(mr, "runnable3").start();
    }
}

輸出結果片段:

thread1:9 thread1:8 ... thread1:0  // thread1 賣完 10 張
thread2:9 thread2:8 ... thread2:0  // thread2 又賣 10 張
thread3:9 ... thread3:0            // thread3 再賣 10 張
runnable1:9 runnable1:8 ... runnable1:0  // 三線程共同賣完 10 張

三、關鍵總結

  1. 數據共享是 Runnable 最大優勢:同一任務邏輯、同一數據源(如庫存、賬戶餘額)必須用 Runnable 或 Callable 實現。
  2. Thread 方式導致數據重複:每個線程擁有獨立 ticks=10,實際上模擬的是「三個窗口各自有 10 張票」,而非「一個窗口共賣 10 張票」。
  3. 實際開發首選 Runnable / Callable:配合線程池(ExecutorService)使用,實現任務與線程分離,支持線程復用、併發控制、異常處理、返回值獲取。
  4. 線程安全尚需額外保障:案例中 ticks-- 非原子操作,高併發下會出現超賣/少賣。生產環境需用 AtomicInteger、synchronized 或 ReentrantLock 保護臨界區。

理解這兩者區別,是寫出正確併發程序的基石。

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