程式碼架構
class E implements Runnable {
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(Thread.currentThread().getName() + "我是:" + x);
}
}
}
public class Threade_15 {
public static void main(String[] args) {
E ee = new E();
Thread t1 = new Thread(ee);
Thread t2 = new Thread(ee);
t1.start();
t2.start();
for (int x = 0; x < 10; x++) {
System.out.println(Thread.currentThread().getName() + "我是:" + x);
}
}
}
執行流程解析
main 執行緒啟動
- 建立
Runnable 實作物件 ee
- 建立兩個
Thread 物件 t1、t2,共用同一 ee
- 呼叫
t1.start()、t2.start() 啟動執行緒(非同步)
main 執行緒繼續執行自己的迴圈
- 三個執行緒(main, t1, t2)並發執行,由 CPU 排程器決定切換時機
關鍵概念說明
Runnable vs Thread 繼承
| 方式 | 實作 Runnable | 繼承 Thread |
| 靈活度 | 高(可繼承其他類別) | 低(單繼承限制) |
| 資源共享 | 自然支援(同一 Runnable 實例) | 需額外設計 |
| 關注點分離 | 任務邏輯與執行緒控制分離 | 混合在一起 |
start() vs run()
start():啟動新執行緒,JVM 呼叫 run(),**非阻塞**
run():直接在當前執行緒呼叫,**阻塞**直到結束
- ❌ 錯誤:`t1.run()` — 不會建立新執行緒
共用 Runnable 實例的效果
t1 和 t2 共用同一個 E 實例 ee,意味著:
- 若
E 有實例變數,兩執行緒會共享(需同步)
- 本例中
run() 只有區域變數 x,無共享資料競爭
輸出特性:非確定性順序
可能的輸出片段:
main我是:0
Thread-0我是:0
Thread-1我是:0
main我是:1
Thread-0我是:1
...
三個執行緒輸出交錯順序不固定,取決於:
- 作業系統排程器
- CPU 核心數
- 系統負載
- JVM 執行緒實作
「交替執行」的誤區與實現
標題提到「交替運行」,但程式碼並未強制交替。真正的交替需同步機制:
方案一:使用 wait/notify
class AlternatingTask implements Runnable {
private final Object lock = new Object();
private int turn = 0; // 0=main, 1=t1, 2=t2
private final int myTurn;
public AlternatingTask(int myTurn) { this.myTurn = myTurn; }
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (lock) {
while (turn != myTurn) {
try { lock.wait(); } catch (InterruptedException e) {}
}
System.out.println(Thread.currentThread().getName() + ":" + i);
turn = (turn + 1) % 3;
lock.notifyAll();
}
}
}
}
方案二:使用 Semaphore(信號量)
Semaphore sMain = new Semaphore(1);
Semaphore sT1 = new Semaphore(0);
Semaphore sT2 = new Semaphore(0);
// 各執行緒:acquire 自己的 semaphore,執行完 release 下一個
// main: sMain.acquire() -> print -> sT1.release()
// t1: sT1.acquire() -> print -> sT2.release()
// t2: sT2.acquire() -> print -> sMain.release()
最佳實踐總結
- 優先使用
Runnable 介面而非繼承 Thread
- 共享資料時必須同步(
synchronized, Lock, volatile, Atomic*)
- 執行緒間協調使用高層建構(
CountDownLatch, CyclicBarrier, Phaser, Semaphore)
- 避免直接操作執行緒狀態(
stop(), suspend(), resume() 已棄用)
- 使用執行緒池(
ExecutorService)管理生命週期
本例展示了最基礎的多執行緒建立方式,理解「並發非決定性」是進階多執行緒編程的前提。
- 上一篇文章: 三數排序與倒三角列印:三種演算法對比與實作
- 下一篇文章: Java 多執行緒經典案例:火車站三窗口同步售票系統
Copyright ©
程式碼之家 All Rights Reserved