大佬們好!我是LKJ_Coding,一枚初級馬牛,正在努力在代碼的叢林中找尋自己的方向。如果你也曾在調試中迷失,或是在文檔中翻滾,那我們一定有許多共同話題可以聊!今天,我帶着滿滿的代碼“乾貨”來和大家分享,學不學無所謂,反正我先吐槽了!

前言

  説起 Java 多線程,很多人第一反應就是那句經典老梗:

“哥們,我寫了個多線程程序,跑得賊快,但我不敢動它。”

  沒錯,多線程這玩意兒,在簡歷上是高大上的標籤,在項目裏卻是“出事找不到根”的潛在爆炸物。你不懂的時候,用起來像開盲盒;你真懂了,才知道:多線程從來不是速度的代名詞,而是複雜性的倍增器。

今天我們不光要“談笑風生”,還要代碼實戰,把 Java 多線程真正掰開揉碎講清楚。你準備好了嗎?


🔥 1. Thread 與 Runnable:你還在用 Thread.start() 嗎?

  Java 最原始的多線程實現方式有兩種:

  1. 繼承 Thread
  2. 實現 Runnable 接口

這兩者的區別,面試官問爛了,但咱得真講明白:本質上都是給 Thread 提供一個“任務”而已,關鍵在於任務與線程的分離是否清晰。


🧪 案例對比

✅ 繼承 Thread

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("我是繼承 Thread 的線程");
    }
}

new MyThread().start();

優點:簡單、直接 缺點:Java 只能單繼承,擴展性弱


✅ 實現 Runnable

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("我是實現 Runnable 的線程");
    }
}

new Thread(new MyRunnable()).start();

優點:任務與線程分離,結構更清晰,可複用性強 缺點:稍微多寫一行代碼(但工程師怕寫代碼你圖什麼)


🧠 建議

  • 實際開發中推薦使用 Runnable 或 Callable(支持返回值)
  • 避免繼承 Thread 導致的類層次混亂
  • 實現 Runnable 更易與線程池集成

⏳ 2. 線程生命週期:你以為 start() 就結束了?天真!

  線程的生命週期,像極了人的職場軌跡:新建 → 就緒 → 運行 → 阻塞 → 死亡


🌀 六大狀態詳解

狀態 説明
New 新建,剛 new 出來,還沒 start
Runnable 可運行,等 CPU 調度
Running 正在執行(但實際在 JVM 中是 Runnable)
Blocked 被鎖阻塞(等別人釋放鎖)
Waiting 無限等待(比如 join)
Timed Waiting 有時限地等待
Terminated 死了,執行完 run 或異常崩了

🌰 示例代碼演示狀態流轉

public class ThreadLifecycle {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (Exception ignored) {}
        });

        System.out.println("1. " + t.getState()); // NEW
        t.start();
        System.out.println("2. " + t.getState()); // RUNNABLE
        Thread.sleep(100);
        System.out.println("3. " + t.getState()); // TIMED_WAITING
        Thread.sleep(1500);
        System.out.println("4. " + t.getState()); // TERMINATED
    }
}

🧱 3. 線程池原理與使用:別再用 new Thread() 了,池子才是正解

  你每次都 new Thread() 就像你每次泡茶都去山裏挑水——能用,但累。

線程池的本質是複用線程資源、控制併發數量、提升性能、方便管理


🧠 Executors 快速入門(不推薦的便捷方式)

ExecutorService pool = Executors.newFixedThreadPool(5);
pool.submit(() -> System.out.println("幹活!"));

注意:生產建議別用 Executors 提供的工廠方法!

  • newFixedThreadPool 可能 OOM(無界隊列)
  • newCachedThreadPool 會無限開線程(容易撐爆)

✅ 推薦方式:自己定義 ThreadPoolExecutor

ExecutorService pool = new ThreadPoolExecutor(
    2,                // 核心線程數
    5,                // 最大線程數
    60L,              // 空閒線程存活時間
    TimeUnit.SECONDS, // 時間單位
    new LinkedBlockingQueue<>(10), // 隊列容量
    Executors.defaultThreadFactory(), // 線程工廠
    new ThreadPoolExecutor.AbortPolicy() // 拒絕策略
);

🧠 拒絕策略有這些(掌握了就是面試利器)

策略名 作用
AbortPolicy 拋出異常(默認)
CallerRunsPolicy 誰提交誰執行
DiscardPolicy 靜默丟棄
DiscardOldestPolicy 丟棄最老的任務,再執行新任務

🧩 4. 併發工具類:不是讓你手寫同步邏輯的

  Java 從不希望你自己搞“線程協調邏輯”,所以從 JDK 5 開始,提供了一堆現成的工具類。

今天我們聚焦三位主角:


① CountDownLatch —— 倒計時器,常用於主線程等待多個子線程

CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        System.out.println("任務完成!");
        latch.countDown(); // 計數減一
    }).start();
}

latch.await(); // 等待計數歸零
System.out.println("全部搞定,收工!");

適合場景:多個任務完成後統一彙總


② CyclicBarrier —— 迴環柵欄,大家一起出發

CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("所有人都準備好了,出發!");
});

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + " 到達集合點");
        try {
            barrier.await(); // 等待其他線程
        } catch (Exception ignored) {}
    }).start();
}

適合場景:多人分段協作,階段性同步


③ Semaphore —— 信號量,控制通行人數

Semaphore sem = new Semaphore(2); // 同時允許2個線程

for (int i = 0; i < 5; i++) {
    new Thread(() -> {
        try {
            sem.acquire(); // 獲取通行證
            System.out.println(Thread.currentThread().getName() + " 進入臨界區");
            Thread.sleep(1000);
            sem.release(); // 釋放通行證
        } catch (Exception ignored) {}
    }).start();
}

適合場景:限流、限資源訪問(如連接池、打印機等)


🧾 結語:併發不是“快”,是“控”

  很多人學多線程,就是為了讓程序“快”。但實際上,多線程真正的難點不在於“怎麼開”,而在於“怎麼關、怎麼管、怎麼同步、怎麼不出事”。

  它像一頭猛獸,控制得好,你程序如虎添翼;控制不好,那就是“併發地報錯、併發地翻車”。

所以,寫多線程代碼前,請捫心自問一句:

“你是真的需要多線程,還是隻是覺得酷?”

好啦,廢話不多説,今天的分享就到這裏!如果你覺得我這“初級馬牛”還挺有趣,那就請給我點個贊、留個言、再三連擊三連哦!讓我們一起“成精”吧!下次見,不見不散!