多線程程式設計的核心挑戰在於「如何正確實現並行」與「如何安全共享資料」。本文系統梳理 Java 多線程實現方式、同步鎖機制、以及效能優化策略。
覆寫 run() 封裝並行邏輯,透過 start() 啟動(切勿直接呼叫 run(),start() 會完成線程初始化再呼叫 run())。
public class TestThread extends Thread {
private static int threadCount = 0;
private int threadNum = ++threadCount;
private int i = 5;
public void run() {
while (true) {
try { Thread.sleep(100); }
catch (InterruptedException e) { System.out.println("Interrupted"); }
System.out.println("Thread " + threadNum + " = " + i);
if (--i == 0) return;
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) new TestThread().start();
}
}
輸出特徵:五個線程交替輸出,證明並行生效。注意:未持有引用的 Thread 物件不會被 GC 回收,因線程註冊機制會隱性持有引用。
突破單一繼承限制,將任務邏輯與線程控制分離:
public class TestThread implements Runnable {
private static int threadCount = 0;
private int threadNum = ++threadCount;
private int i = 5;
public void run() {
while (true) {
try { Thread.sleep(100); }
catch (InterruptedException e) { System.out.println("Interrupted"); }
System.out.println("Thread " + threadNum + " = " + i);
if (--i == 0) return;
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) new Thread(new TestThread()).start();
}
}
this),同一物件的不同線程互斥Class 物件),所有實例共享同一把鎖class TestSynchronized implements Runnable {
public synchronized void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
}
}
public class TestThread {
public static void main(String[] args) {
TestSynchronized r1 = new TestSynchronized();
TestSynchronized r2 = new TestSynchronized();
Thread t1 = new Thread(r1, "t1");
Thread t2 = new Thread(r2, "t2"); // 兩個不同物件
t1.start(); t2.start();
}
}
結果:t1、t2 交替輸出,證明不同物件擁有獨立鎖,可並行執行。
若 t2 = new Thread(r1, "t2") 共用 r1,輸出變為 t1 完整執行完再輪到 t2。
同一線程可同時持有物件鎖(執行 run())與類別鎖(呼叫 static prt()),互不阻塞。
僅同步必要程式碼區塊,提升並行度:
class TestSynchronized implements Runnable {
static int j = 0;
public void run() {
for (int i = 0; i < 5; i++) {
synchronized (this) { // 僅保護 j++ 與列印
System.out.println(Thread.currentThread().getName() + " : " + j++);
}
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
}
}
效果:睡眠操作移出同步區塊,其他線程可在睡眠期間取得鎖並執行,輸出交替更頻繁,吞吐量顯著提升。
Thread 繼承與 Runnable 實作兩種模式,按場景選擇synchronized(this) { ... } 縮小臨界區,平衡安全與效能