Servlet3异步原理
一、什么是异步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异步原理相关推荐
- servlet3异步_Servlet 3的异步Servlet功能
servlet3异步 在深入了解什么是异步Servlet之前,让我们尝试了解为什么需要它. 假设我们有一个Servlet,处理时间很长,如下所示. LongRunningServlet.java pa ...
- servlet3异步 例子_异步Servlet示例
servlet3异步 例子 Async servlet was introduced in Servlet 3. It's a great way to deal with thread starva ...
- 商品详情页系统的Servlet3异步化实践
在京东工作的这一年多时间里,我在整个商品详情页系统(后端数据源)及商品详情页统一服务系统(页面中异步加载的很多服务,如库存服务.图书相关服务.延保服务等)中使用了Servlet3请求异步化模型,总结了 ...
- 【转】商品详情页系统的Servlet3异步化实践
[京东技术]声明:本文转载自微信公众号"开涛的博客",转载务必声明. 在京东工作的这一年多时间里,我在整个商品详情页系统(后端数据源)及商品详情页统一服务系统(页面中异步加载的很多 ...
- MySQL主从复制异步原理以及搭建
MySQL主从复制的原理: 1.首先,MySQL主库在事务提交时会把数据变更作为时间events记录在二进制日志文件binlog中:MySQL主库上的sync_binlog参数控制Binlog日志以什 ...
- javascript等待异步线程完成_JavaScript 中的异步原理
来源:极链科技 作者:周哲 所谓"异步" ,简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段.比如,有一个任务是读取文件进行处理,异 ...
- AJAX异步原理与实现
面试时问到了这个问题,说实话我还是不理解的,只是单单会使用.所以今天我看一下,自己了解下. 看了网上前辈们写的资料,我自己总结归纳ajax的原理和流程如下: 1.AJAX创建异步对象XMLHttpRe ...
- Javascript异步编程之一异步原理
本系列的例子主要针对node.js环境,但浏览器端的原理应该也是类似的. 本人也是Javascript新手,把自己这段时间学习积累的要点总结下来,希望可以对同样在学习Javascript/node.j ...
- python协程异步原理_简单介绍Python的Tornado框架中的协程异步实现原理
Tornado 4.0 已经发布了很长一段时间了, 新版本广泛的应用了协程(Future)特性. 我们目前已经将 Tornado 升级到最新版本, 而且也大量的使用协程特性. 很长时间没有更新博客, ...
- Tomcat7实现Servlet3异步请求
为什么80%的码农都做不了架构师?>>> pom.xml: <dependency><groupId>javax.servlet</groupId ...
最新文章
- Windows HTML本地快速渲染轨迹线
- Spring Boot 2.x基础教程:MyBatis的多数据源配置
- 【Linux】一步一步学Linux——ulimit命令(218)
- MySQL(二)InnoDB的内存结构和特性
- Fiori里前后台ETAG处理
- 【腾讯Bugly干货分享】Android内存优化总结实践
- java 检查目录是否存在_如何检查Java目录是否存在?
- 每日一题(34)—— 线程
- Element UI自定义表单验证 公共提取
- win10创建mysql数据库吗_win10 sqlite3创建的数据库文件在哪
- jQuery中animate()的方法以及$(body).animate({scrollTop:top})不被Firefox支持问题的解决...
- mysql的密码重置
- 谷歌Keras之父连发两文解析深度学习的局限性与未来
- 下载站mime属性设置(让文件可下载)
- linux vim 安装失败,ubuntu安装vim失败怎么办
- 构建Arduino的LoRa远程智能空气质量监测系统
- Flash影片剪辑的属性、深度及动态控制
- 用Python画出奥运五环图 (Python经典编程案例)
- 程序猿之国庆有空吗?
- Android Ibeacon 算法,iBeacon定位算法
热门文章
- 近世代数-群论基础二
- 斗鱼弹幕服务器第三方接入协议v1.6.2,GitHub - yyc-dev/douyu-sdk: DouYu-SDK,一个基于斗鱼弹幕API封装的SDK...
- .gen地图文件的投影编程实现(以墨卡托投影和兰伯特投影为例)
- 高通手机调试烧录—QFIL工具
- 汉字编码计算机,计算机汉字编码,computerbased Chinese codings,音标,读音,翻译,英文例句,英语词典...
- 微信小程序系列(5)如何用微信小程序写一个论坛?贴心代码详解(三)列表页
- 财务分析思维导图模板分享
- 《Redis开发与运维》学习第六章
- 软件开发中的非功能需求类型
- lammps基础教程:Ovito标记原子内部运动方法介绍