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

手寫線程池核心原理實現:ThreadGroup 管理、任務隊列、優雅關閉與拒絕策略

     編輯:Java 綜合教學

為什麼需要線程池

頻繁創建/銷毀線程開銷大(內核對象、棧內存)。線程池復用線程、控制併發數、管理任務隊列,是高併發系統必備組件。

核心設計思路

  • 繼承 ThreadGroup:統一管理池內線程,便於批量中斷、枚舉活動線程。
  • 任務隊列:LinkedList + synchronized 實現生產消費模型。
  • 工作線程:內部類 PooledThread 循環 takeTask() → execute()。
  • 兩種關閉模式:立即關閉(中斷所有) / 優雅關閉(等待任務完成)。

完整實現代碼

1. 任務接口

public interface Task {
    void perform() throws Exception;
}

2. 示例任務

public class MyTask implements Task {
    private final int taskID;
    public MyTask(int id) { this.taskID = id; }
    @Override
    public void perform() throws Exception {
        System.out.println("MyTask " + taskID + ":start");
        Thread.sleep(1000);
        System.out.println("MyTask " + taskID + ":end");
    }
}

3. 線程池主類

public class MyThreadPool extends ThreadGroup {
    private volatile boolean alive = true;
    private final LinkedList<Task> taskQueue = new LinkedList<>();
    private int threadID = 0;
    private static int poolID = 0;

    public MyThreadPool(int numThreads) {
        super("ThreadPool-" + (poolID++));
        setDaemon(true); // 所有線程結束自動銷毀線程組
        for (int i = 0; i < numThreads; i++) new PooledThread().start();
    }

    // 提交任務
    public synchronized void performTask(Task task) {
        if (!alive) throw new IllegalStateException("線程池已關閉");
        if (task != null) {
            taskQueue.addLast(task);
            notify(); // 喚醒一個等待線程
        }
    }

    // 獲取任務(阻塞)
    protected synchronized Task getTask() throws InterruptedException {
        while (taskQueue.isEmpty()) {
            if (!alive) return null; // 池關閉且無任務
            wait();
        }
        return taskQueue.removeFirst();
    }

    // 立即關閉
    public synchronized void close() {
        if (alive) {
            alive = false;
            taskQueue.clear();
            interrupt(); // ThreadGroup.interrupt() → 所有線程中斷
        }
    }

    // 優雅關閉
    public void join() {
        synchronized (this) {
            alive = false;
            notifyAll();
        }
        Thread[] threads = new Thread[activeCount()];
        int count = enumerate(threads);
        for (int i = 0; i < count; i++) {
            try { threads[i].join(); } catch (InterruptedException ignored) {}
        }
    }

    // 工作線程
    private class PooledThread extends Thread {
        PooledThread() { super(MyThreadPool.this, "PooledThread-" + (threadID++)); }

        @Override public void run() {
            while (!isInterrupted()) {
                Task task;
                try { task = getTask(); } catch (InterruptedException e) { return; }
                if (task == null) return; // 池關閉
                try { task.perform(); }
                catch (Exception e) { uncaughtException(this, e); }
            }
        }
    }
}

4. 測試類

public class PoolTest {
    public static void main(String[] args) {
        MyThreadPool pool = new MyThreadPool(3); // 3 個工作線程
        for (int i = 0; i < 10; i++) pool.performTask(new MyTask(i));
        pool.join(); // 等待所有任務完成
    }
}

運行結果分析

MyTask 0:start
MyTask 1:start
MyTask 2:start
MyTask 0:end
MyTask 3:start
MyTask 1:end
MyTask 4:start
...
MyTask 9:end

3 個線程併發執行,任務完成後立即取下一個,體現線程復用。

關鍵點深度解析

機制實現細節
任務入隊synchronized performTask() + notify() 喚醒單線程
任務出隊synchronized getTask() + wait() 釋放鎖阻塞
立即關閉interrupt() 遍歷 ThreadGroup 中斷所有線程
優雅關閉enumerate() 獲取活動線程 → 逐個 join() 等待
異常處理uncaughtException() 捕獲任務異常,防止工作線程意外死亡

與 JDK ThreadPoolExecutor 對比

  • JDK 提供:核心/最大線程數、存活時間、有界隊列、四大拒絕策略、執行鉤子(before/afterExecute)。
  • 手寫版簡化了動態伸縮、拒絕策略、監控指標,但保留了核心調度邏輯,適合面試講解與教學。

生產環境建議

直接使用 Executors 工廠或自定義 ThreadPoolExecutor,配置合理的隊列長度、拒絕策略(如 CallerRunsPolicy)、線程命名(ThreadFactoryBuilder),並接入監控(隊列積壓、活躍線程數、任務耗時)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved