跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

深入解析 Java 线程池的开源扩展方案

对比了 JDK 原生 ThreadPoolExecutor 与 Tomcat、Dubbo、Motan 三大开源框架中线程池的实现差异。重点分析了队列实现(TaskQueue、ExecutorQueue)及任务提交逻辑(offer/force/retryOffer)的定制优化。Tomcat 优先创建线程避免排队,Dubbo 支持 Eager 模式,Motan 借鉴 Tomcat 并提升队列性能。核心在于适配 Web 场景短连接高并发特性,减少请求等待时间。

道系青年发布于 2026/3/27更新于 2026/8/1743 浏览

开篇

Tomcat、Dubbo、Motan 的线程池并非是对 JDK 原生的简单封装,而是基于各自核心场景做了定制化源码扩展。三者均基于 JDK java.util.concurrent.ThreadPoolExecutor 扩展,核心差异在队列实现和线程调度逻辑。默认你懂 JDK 线程池的核心流程(核心线程→队列→临时线程→拒绝策略)。

一、Tomcat(9.0.41)

Tomcat 线程池 vs JDK 原生线程池

Tomcat 的核心线程池实现是 org.apache.tomcat.util.threads.ThreadPoolExecutor(注意:不是 JDK 的 java.util.concurrent.ThreadPoolExecutor),它继承自 JDK 原生类,但做了 3 个关键扩展,适配 Web 场景:

特性JDK 原生 ThreadPoolExecutorTomcat ThreadPoolExecutor
核心线程预启动默认不预启动,需手动调用 prestartCoreThread()可配置 prestartminSpareThreads,自动预启动核心线程
队列满后的处理逻辑队列满→创建临时线程→触发拒绝策略队列满→直接触发拒绝策略(Web 场景优先拒绝,避免请求堆积)
线程空闲销毁逻辑核心线程默认永不销毁可配置 minSpareThreads,核心线程低于该值时不销毁
适用场景通用业务场景(长任务/短任务均可)Web 场景(短连接、高并发、快速响应)
技术要点

Tomcat 线程池的设计核心是'快进快出'——Web 请求都是短任务,优先保证'连接能快速被处理',而非像 JDK 线程池那样'尽量容纳任务',这是调优的核心原则。

Tomcat 线程池的核心实现类是 ThreadPoolExecutor(Tomcat 自定义),核心依赖 TaskQueue(自定义队列),以下只拆 Web 场景最关键的逻辑:

线程池的创建入口

public class StandardThreadExecutor extends LifecycleMBeanBase implements Executor, ResizableExecutor {
    // 核心变量
    protected String namePrefix = "tomcat-exec-";
    // 最大线程数
    protected int maxThreads = 200;
    // 核心线程数
        ;
        ;
    
        ;
    
        ;
    
        Integer.MAX_VALUE;
    
        ;

        LifecycleException {
        .taskqueue =  (.maxQueueSize);
            (.namePrefix, .daemon, .getThreadPriority());
        
        .executor =  (.getMinSpareThreads(), .getMaxThreads(), () .maxIdleTime, TimeUnit.MILLISECONDS, .taskqueue, tf);
        .executor.setThreadRenewalDelay(.threadRenewalDelay);
         (.prestartminSpareThreads) {
            .executor.prestartAllCoreThreads();
        }
        
        .taskqueue.setParent(.executor);
        .setState(LifecycleState.STARTING);
    }
}
protected
int
minSpareThreads
=
25
protected
int
maxIdleTime
=
60000
// tomcat 扩展的线程池
protected
ThreadPoolExecutor
executor
=
null
// 是否预先启动核心线程
protected
boolean
prestartminSpareThreads
=
false
// 默认可堆积的最大任务数
protected
int
maxQueueSize
=
// 任务队列
private
TaskQueue
taskqueue
=
null
protected
void
startInternal
()
throws
this
new
TaskQueue
this
TaskThreadFactory
tf
=
new
TaskThreadFactory
this
this
this
// 创建 tomcat 扩展的线程池,继承自 java.util.concurrent.ThreadPoolExecutor
this
new
ThreadPoolExecutor
this
this
long
this
this
this
this
if
this
this
// 线程池设置到任务队列
this
this
this

线程池的执行入口

public void execute(Runnable command, long timeout, TimeUnit unit) {
    // 提交的任务数 +1
    this.submittedCount.incrementAndGet();
    try {
        // 调用 JDK 线程池的 execute 方法。重点在 TaskQueue 的 offer 方法
        super.execute(command);
    } catch (RejectedExecutionException rx) {
        if (!(super.getQueue() instanceof TaskQueue)) {
            this.submittedCount.decrementAndGet();
            throw rx;
        }
        // 任务队列已积满任务
        TaskQueue queue = (TaskQueue) super.getQueue();
        try {
            // 再次尝试将任务放入队列
            if (!queue.force(command, timeout, unit)) {
                this.submittedCount.decrementAndGet();
                throw new RejectedExecutionException(sm.getString("threadPoolExecutor.queueFull"));
            }
        } catch (InterruptedException x) {
            // 提交的任务数 -1
            this.submittedCount.decrementAndGet();
            throw new RejectedExecutionException(x);
        }
    }
}

核心队列:TaskQueue(Tomcat 自定义的阻塞队列)

这是 Tomcat 线程池和 JDK 原生最核心的差异点,源码核心逻辑:

public class TaskQueue extends LinkedBlockingQueue<Runnable> {
    private transient ThreadPoolExecutor executor;

    public boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {
        if (this.parent != null && !this.parent.isShutdown()) {
            // 此处调用父类 LinkedBlockingQueue 的 offer 方法
            return super.offer(o, timeout, unit);
        } else {
            throw new RejectedExecutionException(sm.getString("taskQueue.notRunning"));
        }
    }

    // 重写 offer 方法:Web 场景下,队列满时直接返回 false,触发拒绝策略
    public boolean offer(Runnable o) {
        if (this.parent == null) {
            return super.offer(o);
        } else if (this.parent.getPoolSize() == this.parent.getMaximumPoolSize()) {
            // 如果创建的线程数等于最大线程数,放入任务队列(此时只能排队等待处理)
            return super.offer(o);
        } else if (this.parent.getSubmittedCount() <= this.parent.getPoolSize()) {
            // 提交的任务数小于核心线程数,放入队列(此时核心线程足以处理提交的任务,不需要创建临时线程)
            return super.offer(o);
        } else {
            // 创建的线程数小于最大线程数,返回 false,此时提交的任务不会排队,而是创建临时线程;否则放入队列
            return this.parent.getPoolSize() < this.parent.getMaximumPoolSize() ? false : super.offer(o);
        }
    }
}
源码解读

JDK 原生线程池的逻辑是'核心线程→队列→临时线程→拒绝',而 Tomcat 通过重写 offer 方法,改成了'核心线程→临时线程(直到 maxThreads)→队列→拒绝'——这意味着 Tomcat 会优先创建线程处理请求,而非让请求排队,完美适配 Web 请求'短、快'的特性,减少请求排队等待时间。

核心扩展:预启动核心线程

Tomcat 线程池支持配置 prestartminSpareThreads="true",源码层面会在初始化时调用。预启动核心线程能避免'首次请求创建线程的开销'——生产中建议开启,尤其是秒杀、活动等突发流量场景。

public void prestartAllCoreThreads() {
    int n = prestartCoreThread();
    while (n < getCorePoolSize()) { 
        n += prestartCoreThread();
    }
}

二、Dubbo(3.3.0)

与 Tomcat 中线程池的实现类似。

org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool#getExecutor

public Executor getExecutor(URL url) {
    String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
    int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
    int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);
    int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
    int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);
    // 初始化队列和线程池
    TaskQueue<Runnable> taskQueue = new TaskQueue<>(queues <= 0 ? 1 : queues);
    EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(cores, threads, alive, TimeUnit.MILLISECONDS, taskQueue, new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
    taskQueue.setExecutor(executor);
    return executor;
}

org.apache.dubbo.common.threadpool.support.eager.EagerThreadPoolExecutor#execute

public void execute(Runnable command) {
    if (command == null) {
        throw new NullPointerException();
    }
    // 提交的任务数 +1
    submittedTaskCount.incrementAndGet();
    try {
        super.execute(command);
    } catch (RejectedExecutionException rx) {
        // retry to offer the task into queue
        final TaskQueue queue = (TaskQueue) super.getQueue();
        try {
            // 拒绝之后再次尝试放入队列
            if (!queue.retryOffer(command, 0, TimeUnit.MILLISECONDS)) {
                submittedTaskCount.decrementAndGet();
                // 任务数 -1
                throw new RejectedExecutionException("Queue capacity is full.", rx);
            }
        } catch (InterruptedException x) {
            submittedTaskCount.decrementAndGet();
            throw new RejectedExecutionException(x);
        }
    } catch (Throwable t) {
        // decrease any way
        submittedTaskCount.decrementAndGet();
        throw t;
    }
}

org.apache.dubbo.common.threadpool.support.eager.TaskQueue#offer

public boolean offer(Runnable runnable) {
    if (executor == null) {
        throw new RejectedExecutionException("The task queue does not have executor!");
    }
    // 当前启动的线程数
    int currentPoolThreadSize = executor.getPoolSize();
    // 提交的任务数小于核心线程数,说明核心线程足以处理,放入队列,让核心线程处理
    if (executor.getSubmittedTaskCount() < currentPoolThreadSize) {
        return super.offer(runnable);
    }
    // 已创建的线程数小于最大线程数,放回 false,不会将任务放入队列,而是创建临时线程
    if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
        return false;
    }
    // 直接放入队列,排队
    return super.offer(runnable);
}

默认拒绝策略

org.apache.dubbo.common.threadpool.support.AbortPolicyWithReport#rejectedExecution

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    String msg = String.format("Thread pool is EXHAUSTED! Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d), Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!",
            this.threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(), e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(), this.url.getProtocol(), this.url.getIp(), this.url.getPort());
    logger.warn("0-1", "too much client requesting provider", "", msg);
    if (Boolean.parseBoolean(this.url.getParameter("dump.enable", Boolean.TRUE.toString()))) {
        this.dumpJStack();
    }
    // 事件监听机制,可扩展 ThreadPoolExhaustedListener,监听 ThreadPoolExhaustedEvent 事件
    this.dispatchThreadPoolExhaustedEvent(msg);
    throw new RejectedExecutionException(msg);
}

三、Motan(1.2.0)

com.weibo.api.motan.core.StandardThreadExecutor

继承 JDK 的线程池,设计思路借鉴于 Tomcat。

队列 ExecutorQueue,继承 LinkedTransferQueue,能保证更高性能,相比 LinkedBlockingQueue 有明显提升。

public StandardThreadExecutor(int coreThreads, int maxThreads, long keepAliveTime, TimeUnit unit, int queueCapacity, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
    // 初始化
    super(coreThreads, maxThreads, keepAliveTime, unit, new ExecutorQueue(), // 任务队列,继承自 LinkedTransferQueue
            threadFactory, handler);
    ((ExecutorQueue) getQueue()).setStandardThreadExecutor(this);
    // 统计提交的任务数
    submittedTasksCount = new AtomicInteger(0);
    // 可以提交的最大任务数:队列长度数 + 最大线程数
    maxSubmittedTaskCount = queueCapacity + maxThreads;
}
public void execute(Runnable command) {
    int count = submittedTasksCount.incrementAndGet();
    // 超过可以提交的任务数,进行 reject
    if (count > maxSubmittedTaskCount) {
        submittedTasksCount.decrementAndGet();
        getRejectedExecutionHandler().rejectedExecution(command, this);
    }
    try {
        super.execute(command);
    } catch (RejectedExecutionException rx) {
        // 再次尝试放入队列
        if (!((ExecutorQueue) getQueue()).force(command)) {
            submittedTasksCount.decrementAndGet();
            getRejectedExecutionHandler().rejectedExecution(command, this);
        }
    }
}

com.weibo.api.motan.core.ExecutorQueue#force

public boolean force(Runnable o) {
    if (threadPoolExecutor.isShutdown()) {
        throw new RejectedExecutionException("Executor not running, can't force a command into the queue");
    }
    // 再次放入任务队列
    return super.offer(o);
}
public boolean offer(Runnable o) {
    // 当前线程数
    int poolSize = threadPoolExecutor.getPoolSize();
    // 当前线程数已达到最大线程数,放入队列
    if (poolSize == threadPoolExecutor.getMaximumPoolSize()) {
        return super.offer(o);
    }
    // 提价的任务数小于等于核心线程,放入队列,让核心线程处理
    if (threadPoolExecutor.getSubmittedTasksCount() <= poolSize) {
        return super.offer(o);
    }
    // 当前线程数小于最大线程数,返回 false,即启动临时线程,处理任务,不再排队
    if (poolSize < threadPoolExecutor.getMaximumPoolSize()) {
        return false;
    }
    // 放入队列
    return super.offer(o);
}

目录

  1. 开篇
  2. 一、Tomcat(9.0.41)
  3. Tomcat 线程池 vs JDK 原生线程池
  4. 技术要点
  5. 源码解读
  6. 二、Dubbo(3.3.0)
  7. 三、Motan(1.2.0)
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • LLaMA Factory 多模态微调实践
  • Python 项目安装 OpenAI 库详细指南
  • Elasticsearch + Kibana 实战指南:从安装部署到 C++ 客户端封装
  • LangChain PyPDFLoader 实战与 PDF 图片提取解析
  • Visual C++ 运行库安装与 DLL 缺失问题解决指南
  • Claude Code 高级编程技巧实战项目详解
  • Llama.cpp 低配置电脑部署大模型指南
  • VS Code + GitHub Copilot 避坑指南:从安装配置到最佳实践
  • Web 版 IM 聊天信息加密的三种实战方案
  • Java 数据类型、运算符与方法核心要点总结
  • RVC 语音变声器快速上手:AI 翻唱与实时变声教程
  • OpenClaw 上下文变短的原因与扩容做法
  • AR 技术在电力配电运维中的应用与解决方案
  • 在 Cursor 中配置并使用 MCP 服务进行自动化开发
  • 机器人第一性原理:技术演进的本构逻辑与实现路径
  • GitHub Copilot 实战配置与指令详解
  • Impala 分布式环境性能优化实战指南(下)
  • AI Harness 工程:AI Agent 生产级架构新范式
  • C++ 继承机制详解与实战
  • LLaMA Factory 本地部署与依赖安装指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online