27 | 新特性:Tomcat如何支持异步Servlet?

Posted IT编程学习栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了27 | 新特性:Tomcat如何支持异步Servlet?相关的知识,希望对你有一定的参考价值。

通过专栏前面的学习我们知道,当一个新的请求到达时,Tomcat 和 Jetty 会从线程池里拿出一个线程来处理请求,这个线程会调用你的 Web 应用,Web 应用在处理请求的过程中,Tomcat 线程会一直阻塞,直到 Web 应用处理完毕才能再输出响应,最后 Tomcat 才回收这个线程。

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

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

今天我们就来学习一下如何开发一个异步 Servlet,以及异步 Servlet 的工作原理,也就是 Tomcat 是如何支持异步 Servlet 的,让你彻底理解它的来龙去脉。

异步 Servlet 示例

我们先通过一个简单的示例来了解一下异步 Servlet 的实现。


  
    
    
  

@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)


public class AsyncServlet extends HttpServlet {




//Web 应用线程池,用来处理异步 Servlet


ExecutorService executor = Executors.newSingleThreadExecutor();




public void service(HttpServletRequest req, HttpServletResponse resp) {


//1. 调用 startAsync 或者异步上下文


final AsyncContext ctx = req.startAsync();




// 用线程池来执行耗时操作


executor.execute(new Runnable() {




@Override


public void run() {




// 在这里做耗时的操作


try {


ctx.getResponse().getWriter().println("Handling Async Servlet");


} catch (IOException e) {}




//3. 异步 Servlet 处理完了调用异步上下文的 complete 方法


ctx.complete();


}




});


}


}