一、什么是异步Servlet

当一个新的请求到达时,Tomcat会从线程池里拿出一个线程来处理请求,这个线程会调用你的Web应用,Web应用在处理请求的过程中,Tomcat线程会一直阻塞,直到Web应用处理完毕才能再输出响应,最后Tomcat才回收这个线程

假如你的Web应用需要较长的时间来处理请求(比如数据库查询或者等待下游的服务调用返回),那么Tomcat线程一直不回收,会占用系统资源,在极端情况下会导致线程饥饿,也就是说Tomcat没有更多的线程来处理新的请求

那该如何解决这个问题呢?

Servlet3.0中引入的异步Servlet。主要是在Web应用里启动一个单独的线程来执行这些比较耗时的请求,而Tomcat线程立即返回,不再等待Web应用将请求处理完,这样Tomcat线程可以立即被回收到线程池,用来响应其他请求,降低了系统的资源消耗,同时还能提高系统的吞吐量

二、异步Servlet示例

SpringBoot启动类添加@ServletComponentScan注解,扫描Servlet

@ServletComponentScan
@SpringBootApplication
public class AsyncServletApplication {public static void main(String[] args) {SpringApplication.run(AsyncServletApplication.class, args);}}

异步Servlet

@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {//Web应用线程池,用来处理异步ServletExecutorService executor = Executors.newSingleThreadExecutor();@Overridepublic void service(HttpServletRequest req, HttpServletResponse resp) {//调用startAsync或者异步上下文AsyncContext asyncContext = req.startAsync();//添加AsyncListenerasyncContext.addListener(new AsyncServletListener());//用线程池来执行耗时操作executor.execute(new Runnable() {@Overridepublic void run() {//在这里做耗时的操作try {asyncContext.getResponse().getWriter().println("Handling Async Servlet");} catch (IOException e) {}//异步Servlet处理完了调用异步上下文的complete方法asyncContext.complete();}});}
}

异步Servlet监听

public class AsyncServletListener implements AsyncListener {private static final Logger LOGGER = LoggerFactory.getLogger(AsyncServletListener.class);/*** 异步线程执行完毕时回调** @param asyncEvent* @throws IOException*/@Overridepublic void onComplete(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onComplete");}/*** 异步线程执行超时回调** @param asyncEvent* @throws IOException*/@Overridepublic void onTimeout(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onTimeout");}/*** 异步线程执行出错回调** @param asyncEvent* @throws IOException*/@Overridepublic void onError(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onError");}/*** 异步线程开始执行时回调** @param asyncEvent* @throws IOException*/@Overridepublic void onStartAsync(AsyncEvent asyncEvent) throws IOException {LOGGER.info("AsyncServlet onStartAsync");}
}

上面的代码有三个要点:

  • 通过注解的方式来注册Servlet,除了@WebServlet注解,还需要加上asyncSupported=true的属性,表明当前的Servlet是一个异步Servlet

  • Web应用程序需要调用Request对象的startAsync()方法来拿到一个异步上下文AsyncContext。这个上下文保存了请求和响应对象

  • Web应用需要开启一个新线程来处理耗时的操作,处理完成后需要调用AsyncContext的complete()方法。目的是告诉Tomcat,请求已经处理完成

虽然异步Servlet允许用更长的时间来处理请求,但是也有超时限制的,默认是30秒,如果30秒内请求还没处理完,Tomcat会触发超时机制,向浏览器返回超时错误,如果这个时候你的Web应用再调用asyncContext.complete()方法,会得到一个IllegalStateException异常

三、异步Servlet原理

接收到Request请求之后,由Tomcat工作线程从HttpServletRequest中获得一个异步上下文AsyncContext对象,然后由Tomcat工作线程把AsyncContext对象传递给业务处理线程,同时Tomcat工作线程归还到工作线程池,这一步就是异步开始。在业务处理线程中完成业务逻辑的处理,生成response返回给客户端

在Servlet3.0中虽然处理请求可以实现异步,但是InputStream和OutputStream的IO操作还是阻塞的,当数据量大的Request Body或者Response Body的时候,就会导致不必要的等待。从Servlet3.1以后增加了非阻塞IO,需要Tomcat8.x支持,通过在HttpServletRequest和HttpServletResponse中分别添加ReadListener和WriterListener方式,只有在IO数据满足一定条件时(比如数据准备好时),才进行后续的操作

@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {//Web应用线程池,用来处理异步ServletExecutorService executor = Executors.newSingleThreadExecutor();@Overridepublic void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {//调用startAsync或者异步上下文AsyncContext asyncContext = req.startAsync();//添加AsyncListenerasyncContext.addListener(new AsyncServletListener());ServletInputStream inputStream = req.getInputStream();inputStream.setReadListener(new ReadListener() {@Overridepublic void onDataAvailable() throws IOException {}@Overridepublic void onAllDataRead() throws IOException {//用线程池来执行耗时操作executor.execute(new Runnable() {@Overridepublic void run() {//在这里做耗时的操作try {asyncContext.getResponse().getWriter().println("Handling Async Servlet");} catch (IOException e) {}//异步Servlet处理完了调用异步上下文的complete方法asyncContext.complete();}});}@Overridepublic void onError(Throwable throwable) {}});}
}

参考:

https://time.geekbang.org/column/article/106935

https://blog.csdn.net/wangxindong11/article/details/78591396

https://www.cnblogs.com/davenkin/p/async-servlet.html

Servlet3异步原理相关推荐

  1. servlet3异步_Servlet 3的异步Servlet功能

    servlet3异步 在深入了解什么是异步Servlet之前,让我们尝试了解为什么需要它. 假设我们有一个Servlet,处理时间很长,如下所示. LongRunningServlet.java pa ...

  2. servlet3异步 例子_异步Servlet示例

    servlet3异步 例子 Async servlet was introduced in Servlet 3. It's a great way to deal with thread starva ...

  3. 商品详情页系统的Servlet3异步化实践

    在京东工作的这一年多时间里,我在整个商品详情页系统(后端数据源)及商品详情页统一服务系统(页面中异步加载的很多服务,如库存服务.图书相关服务.延保服务等)中使用了Servlet3请求异步化模型,总结了 ...

  4. 【转】商品详情页系统的Servlet3异步化实践

    [京东技术]声明:本文转载自微信公众号"开涛的博客",转载务必声明. 在京东工作的这一年多时间里,我在整个商品详情页系统(后端数据源)及商品详情页统一服务系统(页面中异步加载的很多 ...

  5. MySQL主从复制异步原理以及搭建

    MySQL主从复制的原理: 1.首先,MySQL主库在事务提交时会把数据变更作为时间events记录在二进制日志文件binlog中:MySQL主库上的sync_binlog参数控制Binlog日志以什 ...

  6. javascript等待异步线程完成_JavaScript 中的异步原理

    来源:极链科技 作者:周哲 所谓"异步" ,简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段.比如,有一个任务是读取文件进行处理,异 ...

  7. AJAX异步原理与实现

    面试时问到了这个问题,说实话我还是不理解的,只是单单会使用.所以今天我看一下,自己了解下. 看了网上前辈们写的资料,我自己总结归纳ajax的原理和流程如下: 1.AJAX创建异步对象XMLHttpRe ...

  8. Javascript异步编程之一异步原理

    本系列的例子主要针对node.js环境,但浏览器端的原理应该也是类似的. 本人也是Javascript新手,把自己这段时间学习积累的要点总结下来,希望可以对同样在学习Javascript/node.j ...

  9. python协程异步原理_简单介绍Python的Tornado框架中的协程异步实现原理

    Tornado 4.0 已经发布了很长一段时间了, 新版本广泛的应用了协程(Future)特性. 我们目前已经将 Tornado 升级到最新版本, 而且也大量的使用协程特性. 很长时间没有更新博客, ...

  10. Tomcat7实现Servlet3异步请求

    为什么80%的码农都做不了架构师?>>>    pom.xml: <dependency><groupId>javax.servlet</groupId ...

最新文章

  1. Windows HTML本地快速渲染轨迹线
  2. Spring Boot 2.x基础教程:MyBatis的多数据源配置
  3. 【Linux】一步一步学Linux——ulimit命令(218)
  4. MySQL(二)InnoDB的内存结构和特性
  5. Fiori里前后台ETAG处理
  6. 【腾讯Bugly干货分享】Android内存优化总结实践
  7. java 检查目录是否存在_如何检查Java目录是否存在?
  8. 每日一题(34)—— 线程
  9. Element UI自定义表单验证 公共提取
  10. win10创建mysql数据库吗_win10 sqlite3创建的数据库文件在哪
  11. jQuery中animate()的方法以及$(body).animate({scrollTop:top})不被Firefox支持问题的解决...
  12. mysql的密码重置
  13. 谷歌Keras之父连发两文解析深度学习的局限性与未来
  14. 下载站mime属性设置(让文件可下载)
  15. linux vim 安装失败,ubuntu安装vim失败怎么办
  16. 构建Arduino的LoRa远程智能空气质量监测系统
  17. Flash影片剪辑的属性、深度及动态控制
  18. 用Python画出奥运五环图 (Python经典编程案例)
  19. 程序猿之国庆有空吗?
  20. Android Ibeacon 算法,iBeacon定位算法

热门文章

  1. 近世代数-群论基础二
  2. 斗鱼弹幕服务器第三方接入协议v1.6.2,GitHub - yyc-dev/douyu-sdk: DouYu-SDK,一个基于斗鱼弹幕API封装的SDK...
  3. .gen地图文件的投影编程实现(以墨卡托投影和兰伯特投影为例)
  4. 高通手机调试烧录—QFIL工具
  5. 汉字编码计算机,计算机汉字编码,computerbased Chinese codings,音标,读音,翻译,英文例句,英语词典...
  6. 微信小程序系列(5)如何用微信小程序写一个论坛?贴心代码详解(三)列表页
  7. 财务分析思维导图模板分享
  8. 《Redis开发与运维》学习第六章
  9. 软件开发中的非功能需求类型
  10. lammps基础教程:Ovito标记原子内部运动方法介绍