ThreadPoolExecutor 深度解析:从核心参数到源码实现的全面剖析

一、引言:为什么需要线程池?

在 Java 中,线程的创建和销毁并非"免费"操作------每个线程的创建都伴随着操作系统内核级的系统调用,默认栈大小为 1MB。如果每次任务都新建线程,频繁的创建销毁会带来巨大的性能开销。

线程池正是为了解决这一问题而生的池化 技术:预先创建一批线程放入"池"中,任务到来时直接复用已有线程,无需等待创建过程。它的核心优势在于:

  • 降低资源消耗:复用已创建的线程,避免频繁创建销毁

  • 提高响应速度:任务到达时无需等待线程创建

  • 提高线程可管理性:统一分配、调优和监控

  • 提供任务排队与拒绝能力:控制并发上限,保护系统稳定性

核心设计思想 :基于生产者-消费者模型 ------提交任务的线程是生产者,线程池中的工作线程是消费者,任务队列(BlockingQueue)是中间的缓冲区。

二、七大核心参数详解

ThreadPoolExecutor 提供了最完整的构造方法,包含 7 个核心参数

java 复制代码
public ThreadPoolExecutor(
    int corePoolSize,              // 核心线程数
    int maximumPoolSize,           // 最大线程数
    long keepAliveTime,            // 空闲线程存活时间
    TimeUnit unit,                 // 时间单位
    BlockingQueue<Runnable> workQueue, // 任务队列
    ThreadFactory threadFactory,   // 线程工厂
    RejectedExecutionHandler handler // 拒绝策略
)

2.1 corePoolSize ------ 核心线程数

线程池的常驻核心线程 数量。可以理解为公司的正式员工 ------无论有没有任务,只要线程池存活,这些线程就会一直存在(除非设置了 allowCoreThreadTimeOut(true))。

  • 如果设置为 0,表示没有任务时线程池中无线程

  • 线程池初始化时不会立即创建 核心线程,而是在任务提交时懒加载创建

2.2 maximumPoolSize ------ 最大线程数

线程池允许创建的最大线程数量 。可以理解为公司的正式员工 + 临时工的总和。

  • 当核心线程已满任务队列已满时,线程池会创建新线程直到达到该值

  • 必须大于等于 corePoolSize

2.3 keepAliveTime + unit ------ 空闲存活时间

非核心线程 空闲后的存活时间。当线程空闲时间超过该值时,多余线程会被销毁,直到线程数等于 corePoolSize

  • 如果设置了 allowCoreThreadTimeOut(true),核心线程也会受此参数影响

  • 适用于任务量波动大的场景

2.4 workQueue ------ 任务队列

用于存储等待执行的任务的阻塞队列。常见实现及特点:

|-------------------------|-----------------|---------------|
| 队列类型 | 特点 | 适用场景 |
| ArrayBlockingQueue | 有界,基于数组,FIFO | 任务量可控,需限制队列长度 |
| LinkedBlockingQueue | 有界/无界,基于链表,FIFO | 吞吐量要求高,任务量波动大 |
| SynchronousQueue | 不存储元素,直接交接 | 任务执行时间短,并发量高 |
| PriorityBlockingQueue | 无界,支持优先级 | 需按优先级执行任务 |
| DelayQueue | 无界,延迟出队 | 定时任务、超时处理 |

2.5 threadFactory ------ 线程工厂

用于创建线程的工厂。默认使用 Executors.defaultThreadFactory()。生产环境建议自定义命名,便于问题定位。

2.6 handler ------ 拒绝策略

当线程池无法接受新任务时(线程数已达最大且队列已满,或线程池已关闭),执行的处理策略。JDK 提供了四种内置策略:

|-----------------------|---------------------------------|-----------|
| 策略 | 行为 | 适用场景 |
| AbortPolicy(默认) | 抛出 RejectedExecutionException | 严格要求任务不丢失 |
| CallerRunsPolicy | 调用者线程直接执行任务 | 减缓任务提交速度 |
| DiscardPolicy | 静默丢弃任务 | 允许部分任务丢失 |
| DiscardOldestPolicy | 丢弃队列头部的任务,重试提交 | 优先处理新任务 |

三、(了解)源码深度剖析

3.1 ctl ------ 一箭双雕的状态控制器

ThreadPoolExecutor 最精妙的设计之一,是用一个 AtomicInteger 同时记录线程池运行状态工作线程数量

java 复制代码
// 核心状态控制字段
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

// 低 29 位表示工作线程数量,高 3 位表示线程池状态
private static final int COUNT_BITS = Integer.SIZE - 3;  // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 000 111...111 (29个1)

// 五种运行状态(高3位)
private static final int RUNNING    = -1 << COUNT_BITS; // 111 000...000
private static final int SHUTDOWN   =  0 << COUNT_BITS; // 000 000...000
private static final int STOP       =  1 << COUNT_BITS; // 001 000...000
private static final int TIDYING    =  2 << COUNT_BITS; // 010 000...000
private static final int TERMINATED =  3 << COUNT_BITS; // 011 000...000

// 解包方法
private static int runStateOf(int c)     { return c & ~CAPACITY; } // 获取状态
private static int workerCountOf(int c)  { return c & CAPACITY; }  // 获取线程数
private static int ctlOf(int rs, int wc) { return rs | wc; }       // 打包

为什么要这样设计?

将两个变量合并为一个 AtomicInteger ,对 ctl 的 CAS 操作可以原子性地同时修改状态和线程数 ,避免了加锁。workerCount 的理论最大值是 2^29 - 1 ≈ 5.36 亿,在当前硬件条件下完全够用。

五种状态的含义

|----------------|-----------------------------------------------|
| 状态 | 含义 |
| RUNNING | 接受新任务,处理队列任务 |
| SHUTDOWN | 拒绝新任务,处理队列任务 |
| STOP | 拒绝新任务,丢弃队列任务,中断正在执行的任务 |
| TIDYING | 所有任务已终止,workerCount = 0,即将执行 terminated() |
| TERMINATED | terminated() 已执行完成 |

状态转换路径

java 复制代码
RUNNING → SHUTDOWN (调用 shutdown())
RUNNING/SHUTDOWN → STOP (调用 shutdownNow())
SHUTDOWN → TIDYING → TERMINATED (队列和线程都为空)
STOP → TIDYING → TERMINATED (队列为空)

3.2 execute() ------ 任务提交的核心流程

execute() 是线程池最核心的方法,它的执行逻辑分为三步

java 复制代码
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    
    int c = ctl.get();
    
    // 步骤1:工作线程数 < corePoolSize → 创建核心线程
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get(); // 创建失败则重新获取 ctl
    }
    
    // 步骤2:线程池运行中 && 任务入队成功
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 双重检查:入队后可能线程池已关闭
        if (!isRunning(recheck) && remove(command))
            reject(command);  // 回滚并拒绝
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false); // 无工作线程时创建一个
    }
    // 步骤3:队列已满 → 尝试创建非核心线程
    else if (!addWorker(command, false))
        reject(command); // 创建失败 → 执行拒绝策略
}

流程解读

  1. 核心线程优先:工作线程数小于核心数时,直接创建新线程执行任务

  2. 队列缓冲:核心线程已满时,任务入队等待

  3. 双重检查:入队后重新检查状态,防止线程池在入队期间关闭

  4. 扩容:队列已满时,创建非核心线程(不超过最大线程数)

  5. 拒绝:以上都失败时,执行拒绝策略

3.3 addWorker() ------ 线程创建的核心

addWorker 是线程池中最复杂的方法之一,负责原子性地增加工作线程计数并启动线程。

java 复制代码
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 检查线程池状态:非 RUNNING 状态时,只有在 SHUTDOWN 且 firstTask==null 且队列非空时才允许
        if (rs >= SHUTDOWN &&
            !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            // 检查线程数是否超过上限
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // CAS 增加工作线程数
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // CAS 失败,重试
            if (runStateOf(c) != rs)
                continue retry;
        }
    }

    // 创建工作线程并启动
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                int rs = runStateOf(ctl.get());
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive())
                        throw new IllegalThreadStateException();
                    workers.add(w);  // 加入工作线程集合
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();  // 启动线程
                workerStarted = true;
            }
        }
    } finally {
        if (!workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

关键设计

  • 双重循环 + CAS:外层循环检查状态,内层循环 CAS 增加计数

  • core 参数true 表示以 corePoolSize 为上限,false 表示以 maximumPoolSize 为上限

  • 加锁添加workersHashSet,操作时需要加 mainLock 保证线程安全

3.4 Worker ------ 工作线程的封装

WorkerThreadPoolExecutor 的内部类,它同时实现了 Runnable 和继承了 AQS

java 复制代码
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
    final Thread thread;      // 实际的执行线程
    Runnable firstTask;       // 初始任务(可为 null)
    volatile long completedTasks; // 已完成任务数

    Worker(Runnable firstTask) {
        setState(-1); // 禁止中断直到 runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }

    public void run() {
        runWorker(this); // 核心执行逻辑
    }
    // ...
}

为什么 Worker 继承 AQS?

Worker 通过 AQS 实现 机制,在执行任务时加锁,确保任务执行的互斥性------一个 Worker 同时只能执行一个任务。

3.5 runWorker() + getTask() ------ 线程的核心循环

runWorker 是工作线程的主循环 ,而 getTask 负责从队列中获取任务:

java 复制代码
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // 允许中断
    boolean completedAbruptly = true;
    try {
        // 核心循环:不断获取任务并执行
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // 检查线程池状态,若为 STOP 则中断线程
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task); // 钩子方法:执行前
                Throwable thrown = null;
                try {
                    task.run(); // 执行任务!
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown); // 钩子方法:执行后
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

private Runnable getTask() {
    boolean timedOut = false;

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 检查是否需要关闭
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);
        // 是否启用超时回收:核心线程超时 或 线程数 > 核心数
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            // timed ? 超时获取 : 阻塞获取
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

核心机制

  1. 线程复用while 循环不断从队列获取任务执行,一个线程可以执行多个任务

  2. 超时回收timedtrue 时,poll 超时返回 null,触发线程退出

  3. 阻塞 vs 超时 :核心线程使用 take() 永久阻塞,非核心线程使用 poll(keepAliveTime) 超时退出

  4. 钩子方法beforeExecuteafterExecute 允许子类扩展

3.6 拒绝策略的源码实现

四种拒绝策略的实现非常简洁:

java 复制代码
// AbortPolicy:直接抛异常
public static class AbortPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " + e.toString());
    }
}

// CallerRunsPolicy:调用者线程直接执行
public static class CallerRunsPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run(); // 注意:是 run() 不是 start()!
        }
    }
}

// DiscardPolicy:静默丢弃
public static class DiscardPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        // 什么都不做
    }
}

// DiscardOldestPolicy:丢弃队列头部任务,重试提交
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}

注意CallerRunsPolicy 调用的是 Runnable.run() 而非 Thread.start()不会创建新线程,由提交任务的线程同步执行。

四、钩子方法 ------ 扩展的无限可能

ThreadPoolExecutor 提供了三个受保护的钩子方法,允许子类在不修改核心逻辑的情况下扩展功能:

java 复制代码
// 任务执行前调用
protected void beforeExecute(Thread t, Runnable r) { }

// 任务执行后调用(无论是否抛出异常)
protected void afterExecute(Runnable r, Throwable t) { }

// 线程池完全终止后调用
protected void terminated() { }

典型应用场景

  • 记录任务执行耗时(监控)

  • 清理 ThreadLocal 变量

  • 收集统计信息

  • 资源初始化和释放

java 复制代码
// 自定义线程池:带监控
public class MonitorThreadPool extends ThreadPoolExecutor {
    private final AtomicLong totalTime = new AtomicLong(0);
    private final AtomicLong taskCount = new AtomicLong(0);

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        // 在 ThreadLocal 中记录开始时间
        MDC.put("startTime", String.valueOf(System.currentTimeMillis()));
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        long startTime = Long.parseLong(MDC.get("startTime"));
        long cost = System.currentTimeMillis() - startTime;
        totalTime.addAndGet(cost);
        taskCount.incrementAndGet();
        MDC.remove("startTime");
    }

    public double getAvgTaskTime() {
        long count = taskCount.get();
        return count == 0 ? 0 : totalTime.get() / (double) count;
    }
}

⚠️ 警告 :钩子方法中不要抛出未捕获的异常,否则会导致工作线程退出。

五、生命周期管理

5.1 shutdown() vs shutdownNow()

|-----------------|-----------------------------|-------------------------|
| 方法 | 行为 | 状态变化 |
| shutdown() | 不再接受新任务,继续处理队列中已有任务 | RUNNING → SHUTDOWN |
| shutdownNow() | 不再接受新任务,丢弃队列中所有任务,中断正在执行的线程 | RUNNING/SHUTDOWN → STOP |

java 复制代码
// 优雅关闭示例
ExecutorService pool = new ThreadPoolExecutor(...);

// 第一阶段:禁止新任务提交
pool.shutdown();

try {
    // 第二阶段:等待已有任务完成(最多等待 60 秒)
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
        // 第三阶段:强制关闭
        pool.shutdownNow();
        // 再次等待
        if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
            System.err.println("线程池未能正常关闭");
        }
    }
} catch (InterruptedException e) {
    pool.shutdownNow();
    Thread.currentThread().interrupt();
}

六、Executors 的陷阱与自定义线程池

6.1 为什么禁止使用 Executors?

《阿里巴巴 Java 开发手册》明确规定:线程池不允许使用 Executors 去创建,而要通过 ThreadPoolExecutor 的方式

|---------------------------|-------------------------------------------------------------------------|------------------|
| Executors 方法 | 底层实现 | 风险 |
| newFixedThreadPool | corePoolSize = maxPoolSizeLinkedBlockingQueue(无界) | 队列无限堆积 → OOM |
| newSingleThreadExecutor | 同上 | 同上 |
| newCachedThreadPool | corePoolSize = 0maxPoolSize = Integer.MAX_VALUESynchronousQueue | 线程无限创建 → OOM |
| newScheduledThreadPool | 同上 | 同上 |

6.2 正确的自定义方式

java 复制代码
public class ThreadPoolConfig {
    
    public static ExecutorService createCustomPool() {
        // 获取 CPU 核心数
        int processors = Runtime.getRuntime().availableProcessors();
        
        // CPU 密集型:corePoolSize = CPU核心数 + 1
        // I/O 密集型:corePoolSize = CPU核心数 * 2(或更大)
        int corePoolSize = processors + 1;
        int maxPoolSize = corePoolSize * 2;
        
        return new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            60L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000), // ✅ 有界队列,防止 OOM
            new NamedThreadFactory("biz-pool"), // ✅ 命名线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy() // ✅ 合理的拒绝策略
        );
    }
}

// 自定义命名线程工厂
class NamedThreadFactory implements ThreadFactory {
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    NamedThreadFactory(String name) {
        this.namePrefix = name + "-";
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
        t.setDaemon(false);
        t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

七、最佳实践与避坑指南

✅ 推荐做法

  1. 始终使用 ThreadPoolExecutor 自定义创建,明确所有参数

  2. 使用有界队列 (如 ArrayBlockingQueue),防止任务堆积导致 OOM

  3. 自定义线程工厂并命名,便于问题定位

  4. 根据任务类型设置线程数

    1. CPU 密集型:corePoolSize = CPU核心数 + 1

    2. I/O 密集型:corePoolSize = CPU核心数 * 2(需根据实际 I/O 等待时间调整)

  5. 选择合适的拒绝策略 :关键业务用 CallerRunsPolicy,可容忍丢失用 DiscardPolicy

  6. 优雅关闭 :使用 shutdown() + awaitTermination() 组合

  7. 监控线程池状态 :通过 getActiveCount()getQueue().size() 等方法监控

八、总结

ThreadPoolExecutor 是 Java 并发编程中最核心的类之一,它的设计堪称经典:

1. 精巧的状态管理 :用一个 AtomicInteger 的 32 位同时记录运行状态 (高 3 位)和线程数量(低 29 位),通过 CAS 实现无锁更新。

2. 分层的任务处理:核心线程优先 → 队列缓冲 → 非核心线程扩容 → 拒绝策略,四层机制平滑应对流量波动。

3. 优雅的线程复用runWorker + getTask 循环让工作线程持续从队列获取任务,实现线程的无限复用。

4. 灵活的扩展能力:钩子方法、自定义线程工厂、自定义拒绝策略,赋予了无限扩展的可能。

|----------|--------------------------------|
| 维度 | 设计精髓 |
| 状态控制 | ctl 高 3 位状态 + 低 29 位线程数 |
| 任务执行 | 核心线程 → 队列 → 非核心线程 → 拒绝 |
| 线程复用 | runWorker 循环 + getTask 取任务 |
| 扩展机制 | 钩子方法 + 自定义工厂 + 自定义拒绝策略 |

理解 ThreadPoolExecutor 的源码,不仅能帮你写出更健壮的并发代码,更能让你在面对高并发场景时,知道如何精准地配置线程池参数 ,在资源消耗系统吞吐量之间找到最佳平衡点。

一句话总结ThreadPoolExecutor 是 Java 线程池的"万能钥匙"------它用精妙的设计在线程管理任务调度资源控制之间取得了完美的平衡,是所有高并发系统的基石。

提问:核心线程优先 → 队列缓冲 → 非核心线程扩容 → 拒绝策略,为什么不是先创建非核心线程,再队列缓冲呢?面试该如何回答

这是权衡"资源开销"与"响应速度"后的设计选择。 优先用队列缓冲,是为了避免线程的频繁创建与销毁,因为线程是重量级资源;而先创建非核心线程再入队,会导致线程数快速膨胀,严重浪费系统资源。

下面我把这个问题的面试回答,拆解成三个递进的层次。你可以直接参考第三层的话术。

第一层:最直观的理解(资源开销)

"线程池的设计者认为,阻塞队列的入队操作,其代价远低于创建一个新线程。 因为创建线程需要分配栈内存、进行系统调用(pthread_create),开销很大。所以,线程池的策略是'先尝试用轻量级的缓冲(队列)来应对突发流量,只有在缓冲区也满了,说明压力确实很大时,才使用创建新线程这种'重型武器'来扩容。这能最大化地复用线程资源,控制系统的资源消耗。"

第二层:从任务处理效率看(响应时间)

"如果改成'先创建非核心线程,再队列缓冲',意味着当核心线程繁忙时,系统会立即为每个新任务都创建一个新线程。这会让线程数量非常快地达到 maximumPoolSize。一旦达到上限,所有新任务又会被放入队列。这会导致线程的频繁创建和销毁,反而增加了系统的上下文切换开销,降低了吞吐量。"

"而当前的顺序(核心线程满 → 入队)则提供了一个缓冲平滑期。在队列未满之前,系统不会创建新线程,这给了系统一个应对短暂流量高峰的机会,避免因为瞬间的高并发而过度扩容,造成资源浪费。"

第三层:与阻塞队列特性的配合(核心设计意图)

"这里面有一个容易被忽略的关键点:BlockingQueueoffer 方法是非阻塞的。当核心线程满时,调用 offer 尝试将任务放入队列,如果队列未满,任务就成功入队了,整个过程非常轻量。如果先创建新线程,就需要将任务提交给一个新创建的线程去执行,这本身就是一个重量级操作。"

"线程池的设计者希望最大程度地利用已有的核心线程来处理任务。因为线程的创建和销毁是有成本的,corePoolSize 正是为了维持一个稳定的'常驻工人'数量。只有当任务多到连队列这个'缓冲区'都塞不下时,才说明确实超出了系统的常规处理能力,这时才需要临时工(非核心线程)来帮忙。'队列缓冲'是线程池伸缩性管理的第一道防线,它确保了系统在面对突发流量时,优先选择'排队等待'而非'盲目扩容'。"

一句话总结:因为线程是重型资源,队列缓冲是轻量级操作。优先入队是'节流',尽量复用已有线程;只有在队列压力过大时,才'开源'创建新线程。这个顺序是线程池进行资源管理和流量控制的核心策略。

相关推荐
谢尔登1 小时前
分享一些我常用的Skill
java·人工智能·python·actionscript
一位狮子座的程序员1 小时前
如何用RAG解决AI智能体的知识盲区?
开发语言·c#
AaronJonah1 小时前
企业级线程池 traceId 闭环:上下文传递与全链路追踪实战
java·线程池·traceid跨线程传递
吹什么轩2 小时前
c++复习:模拟实现list来更好的理解和应用list
开发语言·c++
程序员黑豆2 小时前
Java入门第一步:从零开始编写你的第一个Hello World程序
java·前端·ai编程
小白学大数据2 小时前
Python 爬虫实战:抓取汽车之家二手车成交价格与里程数据
开发语言·爬虫·python·汽车
深盾科技_Virbox2 小时前
软件加密工具怎么选:试用验证、采购成本与授权范围
开发语言·安全·软件需求
A_cainiao_A2 小时前
C++20:std::stop_source让线程说停就听
开发语言·c++20
Jazz_z2 小时前
如何用Python将彩色PDF一键转为黑白(灰度)
java·python·pdf