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

Java 多線程編程精要:Thread 類與 Runnable 介面實現線程詳解

     編輯:Java 相關知識

Java 內建多線程支援使併發編程相對簡單,但核心概念必須掌握。本文詳細解析Thread 繼承法、Runnable 介面法、synchronized 關鍵字三大基石,並說明 main() 也是一條線程。

一、Thread 類繼承法

Thread 為具體類,覆寫 run() 定義線程邏輯,調用 start() 啟動 (非直接調用 run())。


class TimePrinter extends Thread {
    int pauseTime; String name;
    public TimePrinter(int x, String n) { pauseTime = x; name = n; }
    @Override public void run() {
        while (true) {
            try {
                System.out.println(name + ": " + new Date());
                Thread.sleep(pauseTime);
            } catch (Exception e) { System.out.println(e); }
        }
    }
    public static void main(String[] args) {
        new TimePrinter(1000, "Fast Guy").start(); // 1秒輸出一次
        new TimePrinter(3000, "Slow Guy").start(); // 3秒輸出一次
        // main 線程繼續執行 (此處 main 結束但 JVM 存活因非守護線程)
    }
}

輸出:兩條線程交替打印時間,間隔分別 1s/3s。

缺點:Java 單繼承限制,若類已有父類則無法使用;強加類層次結構。

二、Runnable 介面法 (推薦)

實現 Runnable 介面 (run()),再包裝進 Thread 建構子。


class TimePrinter implements Runnable {
    int pauseTime; String name;
    public TimePrinter(int x, String n) { pauseTime = x; name = n; }
    @Override public void run() { /* 同上 */ }
    public static void main(String[] args) {
        new Thread(new TimePrinter(1000, "Fast Guy")).start();
        new Thread(new TimePrinter(3000, "Slow Guy")).start();
    }
}

優點:
1. 避免單繼承限制,類可自由繼承其他父類。
2. 邏輯與線程控制分離,符合「組合優於繼承」。
3. 同一 Runnable 實例可提交給多個線程/線程池複用。

三、synchronized 關鍵字:解決共享資料競態

每個 Java 物件天生關聯一把監視器鎖。方法加 synchronized 即獲取該鎖,同一時間僅允許一線程執行該物件的同步方法。

經典銀行賬戶問題


public class Account {
    String holderName; float amount;
    public Account(String name, float amt) { holderName = name; amount = amt; }
    // 非同步版:併發存取會導致金額錯誤
    public void deposit(float amt) { amount += amt; }
    public void withdraw(float amt) { amount -= amt; }
    public float checkBalance() { return amount; }
}

併發場景:夫妻倆同時在不同 ATM 操作同一聯名賬戶,deposit/withdraw 交錯導致金額損壞。

同步修正版


public class Account {
    String holderName; float amount;
    public Account(String name, float amt) { holderName = name; amount = amt; }
    public synchronized void deposit(float amt) { amount += amt; }
    public synchronized void withdraw(float amt) { amount -= amt; }
    public float checkBalance() { return amount; } // 唯讀無需同步
}

機制:deposit 與 withdraw 共用 this 鎖,互斥執行。checkBalance 無同步,不阻塞寫操作,寫操作也不阻塞它 (但可能讀到舊值,若需強一致性可加 synchronized 或用 volatile/AtomicReference)。

核心概念總結

概念說明
Thread vs RunnableThread 繼承法簡單但受單繼承限制;Runnable 介面法靈活、可復用、推薦生產使用
start() vs run()start() 啟動新線程並異步調用 run();直接調用 run() 只是普通方法調用,不會開新線程
main 線程JVM 啟動主線程執行 main(),用戶線程結束前 JVM 不退出
物件鎖每個物件一把鎖,synchronized 實例方法鎖 this,靜態方法鎖 Class 物件
同步粒度僅同步必要的共享狀態讀寫操作,避免過度同步降低併發度

進階延伸

  • volatile:保證可見性,不保證原子性 (適用於單寫多讀標誌位)。
  • java.util.concurrent:AtomicInteger、ReentrantLock、CountDownLatch、ThreadPoolExecutor 等高級併發工具,優先於低級 synchronized/wait/notify。
  • 線程安全集合:ConcurrentHashMap、CopyOnWriteArrayList 等替代手動同步。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved