当前位置: 首页 > news >正文

tomcat异步请求机制

tomcat异步请求机制

一、什么是 Tomcat 异步请求

Servlet 3.0(Java EE 6)开始引入了异步请求(Asynchronous Request Processing)机制,Tomcat 从 7.x 开始支持该特性。

在传统 Servlet 模型中,一个 HTTP 请求会一直占用一个 Tomcat 工作线程,直到业务处理完成并返回响应。

客户端│▼
Tomcat 工作线程│├──业务处理(可能几十秒)│└──返回响应

如果业务处理时间较长(例如调用远程接口、AI 大模型、消息等待等),Tomcat 工作线程会一直处于阻塞状态。

异步请求的核心思想是:

让处理请求的 Tomcat 工作线程尽快归还线程池,由其他线程继续完成业务,并返回响应。

因此,一个请求生命周期中可能会涉及多个线程:

  • Tomcat 工作线程(接收请求)
  • 业务线程(真正执行业务,然后返回响应或者分发给另外一个Servlet)

对应流程如下:

客户端│▼
Tomcat线程(T1)│
startAsync()│
释放Tomcat线程│
──────────────
业务线程(T2)│
业务处理│
dispatch()/complete()│▼
客户端

需要注意:

异步请求并不会让业务自动变快,它只是减少了 Tomcat 工作线程的占用时间,提高服务器的并发能力。

二、适用于哪些场景

Tomcat 异步请求主要适用于耗时操作

典型场景包括:

1. 调用远程服务

例如:

  • RPC 调用
  • HTTP 接口调用
  • OpenFeign
  • Dubbo

等待远程响应期间,没有必要一直占用 Tomcat 线程。

2. 数据库存储较慢

例如:

  • 大批量写库
  • 导出数据
  • 复杂统计 SQL

可以让业务线程完成处理,再恢复请求。

3. AI 大模型

例如:

  • ChatGPT
  • DeepSeek
  • Claude

模型生成答案通常持续数秒甚至数分钟,非常适合异步请求。

如果结合:

  • ResponseBodyEmitter
  • SseEmitter

还可以实现流式输出。

4. SSE

Server-Sent Events:

服务器持续向浏览器推送数据。

Spring MVC 中:

SseEmitter

底层就是基于 Servlet AsyncContext。

三、使用示例

业务线程自己写响应

主要流程如下:

  1. @WebServlet开启异步支持
  2. Servlet中调用startAsync()方法开启异步
  3. 业务线程处理逻辑,写响应,最后调用complete()方法结束异步过程

开启异步:

@WebServlet(value = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) {// 开启异步, 这样容器就不会在servlet执行完后主动关闭响应流了AsyncContext asyncContext = request.startAsync();executor.execute(() -> {response.setContentType("text/plain");try {// doSomething(耗时操作)response.getWriter().write("Hello Async");} catch (Exception e) {try {response.getWriter().write("failed");} catch (IOException ex) {throw new RuntimeException(ex);}} finally {// 告知servlet容器可以关闭响应了asyncContext.complete();}});}
}

在这个例子中,由于servlet本身没有任何耗时动作,servlet执行完后,tomcat工作线程就会被释放掉,但是对应的响应流是没有被关闭的,只有调用asyncContext.complete()后,容器才会执行清理动作,关闭响应流。

转发给另外一个servlet执行逻辑

当前servlet中的业务线程可以做一些预处理逻辑,然后再转发给另外一个servlet完成最终的响应,spring mvc中的异步底层都是这么玩的。进行转发后,就不用再调用asyncContext.complete()了,转发后的servlet执行完,容器会自动调用syncContext.complete()

Async2Servlet.java

@Slf4j
@WebServlet(value = "/async2", asyncSupported = true)
public class Async2Servlet extends HttpServlet {private final ExecutorService executor = Executors.newFixedThreadPool(10);@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) {log.info("{}", request);// 开启异步AsyncContext asyncContext = request.startAsync();executor.execute(() -> {// doSomething(预处理逻辑)// 通过保存预处理结果到request中request.setAttribute("result", "success");// 转发给/async3 servlet  (不带参数则是转发给自己)asyncContext.dispatch("/async3");});}
}

Async3Servlet.java

@Slf4j
@WebServlet(value = "/async3")
public class Async3Servlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {// request为ApplicationHttpRequest实例if (request instanceof HttpServletRequestWrapper) {log.info("{}", ((HttpServletRequestWrapper)request).getRequest());}response.setContentType("text/plain");// 获取预处理结果String result = (String) request.getAttribute("result");response.getWriter().write(result);}
}

转发后的servlet接收到的request、response都被包了一层,分别为ApplicationHttpRequestApplicationHttpResponse,但是内部持有的request以及response和转发之前的是同一个对象,因此可以拿到之前的请求参数,同一个响应流。

Async3Servlet的响应结果就是请求Async2Servlet的结果。

四、超时机制

Tomcat 异步请求支持超时控制,默认为30s,也可以单独设置,如下所示

AsyncContext async = request.startAsync();
async.setTimeout(30000);

超时后会触发:

async.addListener(new AsyncListener() {@Overridepublic void onTimeout(AsyncEvent event) {// 超时回调可以写响应,也可以进行转发,响应超时之后的结果}});

需要注意的是:

  • 超时并不会强制停止业务线程,因此,业务线程需要自行处理中断、取消任务或检查超时状态。
  • 异步Servlet中只要调用了complete或者dispatch方法,超时就失效了,complete很好理解,代表异步过程结束了;调用完dispatch,比如转发后的servlet超时了,是不会触发onTimeout回调的。
  • tomcat后台中有一个定时任务会检查异步过程是否超时,若超时,会派发一个超时事件给工作线程执行,工作线程看到事件类型是超时,便会触发onTimeout回调,源码位置: AbstractProtocol.startAsyncTimeout()。

超时示例

@Slf4j
@WebServlet(value = "/async4", asyncSupported = true)
public class Async4Servlet extends HttpServlet {private final ExecutorService executor = Executors.newFixedThreadPool(10);@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) {// 开启异步AsyncContext asyncContext = request.startAsync();// 设置1秒超时asyncContext.setTimeout(1000);Future<?> future = executor.submit(() -> {boolean isInterrupted = false;try {// 模拟超时操作TimeUnit.SECONDS.sleep(3);// 保存预处理结果到request中request.setAttribute("result", "success");} catch (InterruptedException e) {isInterrupted = true;}/** 如果被中断了, 说明超时了, 就不要再调用转发了, 此时异步过程已经超时结束了,再调用会报错* 超时回调中,会将future取消,进而中断线程*/if (!isInterrupted) {asyncContext.dispatch("/async3");}});asyncContext.addListener(new AsyncListener() {@Overridepublic void onComplete(AsyncEvent event)  {log.info("======= onComplete=========");}@Overridepublic void onTimeout(AsyncEvent event)  {/** 这里回调如果不自己处理超时的响应, servlet容器会转发给统一的错误处理* spring boot中为/error*/// 中断异步线程, 取消任务log.info("======= onTimeout=========");future.cancel(true);request.setAttribute("result", "timeout");asyncContext.dispatch("/async3");}@Overridepublic void onError(AsyncEvent event)  {}@Overridepublic void onStartAsync(AsyncEvent event) throws IOException {}});}
}

五、总结

Tomcat 异步请求的核心价值不是提高单个请求的执行速度,而是提高服务器整体吞吐量和线程利用率

对于存在大量等待时间的业务(如 RPC、数据库、AI、大文件下载、SSE、长轮询等),异步请求能够显著减少 Tomcat 工作线程的占用,提高系统的并发处理能力。

在 Spring MVC 中,开发者通常无需直接操作 AsyncContext,而是使用 DeferredResultCallableResponseBodyEmitterSseEmitter 等高级抽象即可享受 Servlet 异步机制带来的优势。

理解其底层原理,有助于正确处理线程切换、超时控制、请求恢复以及流式响应等高级场景。

http://www.jsqmd.com/news/1313091/

相关文章:

  • Wand-Enhancer:完全解锁WeMod专业版功能的终极指南
  • 邳州装修半包、全包怎么选?本地靠谱装修公司推荐,首选这家无套路! - 品牌品鉴馆
  • Vxe-Table全局引入的打包体积优化:从性能瓶颈到按需加载实践
  • 稀疏矩阵存储:从三元组顺序表到CSR/CSC格式的原理与应用
  • 3分钟上手:TFT Overlay让你的云顶之弈决策快人一步 [特殊字符]
  • Anthropic自曝Claude模型入侵真实企业系统:AI安全测试的边界在哪里?
  • 2026年五平台实测对比,买二手手机哪个平台靠谱?爱回收为何综合排名第一 - 品牌品鉴馆
  • 终极文档下载神器:3步免费下载百度文库、原创力文档等30+平台文档
  • 泉州全屋石晶定制品牌厂商选哪家更稳妥? - 品牌品鉴馆
  • 看完50篇 AI for DV 论文,我觉得验证工程师暂时安全,但工作已经回不去了
  • 2026沧州管道支吊架生产实力厂商大盘点 正规合规选型避坑指南 多行业工程场景适配优质服务商深度解析 - 产业观察报
  • 莲都防水修缮实测测评:本地适配工艺才是根治漏水关键(2026.8月) - 超人防水
  • WSaiOS综合应用平台工程
  • 2026盐城装修风向标:追求极致性价比,橙意家装饰是你的不二之选! - 钦扬网络
  • DRG Save Editor 终极指南:3步解锁《深岩银河》所有资源与超频模组
  • 评价高的商场LED广告大屏施工怎么选?四川本地厂家推荐与避坑指南 - 优质品牌商家
  • FOC控制系统模块全解析:从坐标变换到SVPWM的完整工作流
  • 衡水各个区均可上门回收欧米加手表15369396611 - 毓典奢品汇回收专家
  • 基于reComputer R1000与FIN框架的工业数据可视化实战:从Modbus采集到动态图形看板
  • Win11下Excel通过ODBC连接MySQL:搭建高效数据分析环境
  • 树莓派Grove Base Hat扩展板:接口标准化与传感器即插即用开发指南
  • 一线观察:家用储能市场口碑好的公司长期发展有哪些细节? - 品牌品鉴馆
  • 真理秩序的重构:基于贾子理论对西方伪学术体系的证伪与新范式奠基——彻底清算波普尔病毒与西方认知殖民的宣言
  • Aitiy全局效率工具:鼠标手势、OCR与快捷操作提升工作流效率
  • 北京lv回收,毓典奢品汇15369396611 - 毓典奢品汇回收专家
  • 【AI广告投放分析黄金法则】:20年实战验证的7大ROI提升策略,错过再等一年
  • 买二手Switch哪个平台便宜?爱回收严选与多平台实测对比 - 品牌品鉴馆
  • 邳州自建房装修哪家专业?靠谱装修公司首选推荐 - 品牌品鉴馆
  • Unity异步编程与依赖注入:UniTask与VContainer组合架构实战
  • 源城区防水修缮实测测评:本地适配工艺才是根治漏水关键(2026.8月) - 超人防水