在 Java 並發編程的世界裡,線程是實現多任務處理的核心單元。掌握線程的基本概念、創建方式以及控制方法,是構建高性能、高併發應用的基石。本文將系統梳理線程的基礎知識,並通過代碼示例幫助你深入理解。
線程,顧名思義,是進程內部的一條順序控制流。一個進程可以包含多個線程,它們共享進程的內存空間和資源,但擁有獨立的棧空間和程序計數器。這就是為什麼多線程能夠在同一個應用程序中同時執行多個任務,而多進程則是在作業系統層面同時運行多個獨立的程序。
在 Java 中,線程通過 java.lang.Thread 類來實現。JVM 啟動時,會自動創建一個由 main 方法定義的主線程。開發者可以通過創建 Thread 實例來啟動新的線程。每個線程的具體執行邏輯封裝在 run() 方法中,這被稱為線程體。關鍵在於:必須調用 start() 方法而非直接調用 run() 來啟動線程,否則只是普通方法調用,不會開啟新的執行路徑。
Java 提供了兩種主流的線程創建方式,各有優勢:
這種方式更靈活,因為它避免了單繼承的限制,且便於多個線程共享同一份數據邏輯。
public class ThreadTheory {
public static void main(String[] args) {
Runner1 runner1 = new Runner1();
Thread thread = new Thread(runner1);
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println("Main Thread:" + i);
}
}
}
class Runner1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner1:" + i);
}
}
}
在 Runnable 的 run() 方法中,可通過 Thread.currentThread() 獲取當前執行線程的引用。
直接繼承 Thread 並重寫 run() 方法,代碼結構簡單直觀,但受限於 Java 單繼承機制。
public class ThreadTheory {
public static void main(String[] args) {
Runner2 runner2 = new Runner2();
runner2.start(); // runner2 本身就是線程對象
for (int i = 0; i < 10; i++) {
System.out.println("Main Thread:" + i);
}
}
}
class Runner2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Runner2:" + i);
}
}
}
掌握線程的休眠、中斷與優雅終止,是編寫健壯並發程序的關鍵。
Thread.sleep(long millis) 使當前執行線程暫停指定毫秒數,釋放 CPU 但不釋放鎖(監視器)。若休眠期間被中斷,會拋出 InterruptedException 並清除中斷狀態。
interrupt() 不會強制終止線程,而是設置中斷標誌。若線程處於阻塞狀態(如 sleep()、wait()、join()),會拋出 InterruptedException 並清除標誌;否則僅設置中斷狀態,需代碼主動檢查並響應。
Thread.stop() 已被棄用,因其會導致鎖突然釋放,留下數據不一致風險。推薦使用「標誌位 + 中斷」模式:
public class MyThread extends Thread {
private volatile boolean flag = true; // volatile 保證可見性
public void stopThread() {
this.flag = false;
this.interrupt(); // 若在 sleep 中,配合中斷加速退出
}
@Override
public void run() {
while (flag) {
System.out.println("===當前時間 " + new Date() + "===");
try {
sleep(1000);
} catch (InterruptedException e) {
return; // 捕獲中斷異常,直接退出 run 方法
}
}
}
}
// 使用示例
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(10000);
myThread.stopThread(); // 通過標誌位優雅結束
myThread.join(); // 等待線程真正結束
這樣既保證了線程安全,又能讓線程在完成當前工作單元後有序退出。