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

Java 多線程程式設計實戰(四):Thread 與 Runnable 實現機制詳解

     編輯:Java 相關知識

Java 讓多線程簡單到「幾乎自然」,但仍需掌握核心概念:main() 本身即線程,僅在需要額外並行時建立新線程。本文詳細對比 Thread 繼承與 Runnable 實現兩大模式,並引入 synchronized 保護共享資料。

模式一:繼承 Thread 類別

  • Thread 為具體類別,非抽象類
  • 建立子類別,覆寫 run() 封裝任務邏輯
  • 呼叫 start() 啟動(絕不直接呼叫 run())
import java.util.*;

class TimePrinter extends Thread {
    int pauseTime; String name;
    public TimePrinter(int x, String n) { pauseTime = x; name = n; }
    
    public void run() {
        while (true) {
            try {
                System.out.println(name + ":" + new Date(System.currentTimeMillis()));
                Thread.sleep(pauseTime);
            } catch (Exception e) { System.out.println(e); }
        }
    }
    
    static public void main(String args[]) {
        TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
        tp1.start();
        TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
        tp2.start();
        // main() 線程繼續執行,共三線程並行
    }
}

模式二:實作 Runnable 介面

  • 單一方法 run(),不強加類別繼承體系
  • 任務邏輯與線程控制分離,彈性更高
  • 建立 Thread 時傳入 Runnable 實例
import java.util.*;

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

選擇建議

  • 類別已繼承其他類別 → 必須用 Runnable
  • 傾向組合優於繼承 → 優先 Runnable
  • 簡單獨立任務 → Thread 繼承亦可接受

共享資料同步:銀行帳戶案例

問題:非同步存取導致資料損壞

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 交錯執行導致更新遺失。

解決:synchronized 關鍵字

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; } // 唯讀無需同步
}

運作機制

  • 每個物件運行期關聯一把內建鎖 (monitor/intrinsic lock)
  • synchronized 方法需獲取鎖才能執行,其他同步方法阻塞
  • checkBalance() 未同步:不阻塞寫入,寫入不阻塞讀取(可能讀到舊值,視業務容忍度)

進階提示

  • 同步範圍越小越好:考慮 synchronized(this) { ... } 區塊
  • 高併發讀多寫少場景 → 改用 ReadWriteLock (JDK 1.5+)
  • 複合操作(如轉帳)需額外鎖定整個流程,單一方法同步不足
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved