为什么要使用异步 Servlet,同步 Servlet 阻塞了什么?异步 Servlet 是怎样工作的?
同步 Servlet
先看一个同步 Servlet 的 Demo,代码非常简单,就是模拟了一个 5s 耗时的操作,然后程序打印一段话,记录程序执行时间,通过允许这段代码,我们发现总耗时为:5007 毫秒
@WebServlet(name="SyncServlet",urlPatterns="/SyncServlet")public class SyncServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {long start = System.currentTimeMillis();doSomething(request, response);System.out.println("Sync servlet: " + (System.currentTimeMillis() - start));}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}private void doSomething(HttpServletRequest request, HttpServletResponse response) {try {// 模拟耗时操作TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}try {response.getWriter().append("SyncServlet done");} catch (IOException e) {e.printStackTrace();}}}
异步 Servlet
相同的 Demo,我们启用了异步支持,通过测试,耗时:6 毫秒
@WebServlet(name = "AsyncServlet", urlPatterns = "/AsyncServlet", asyncSupported = true)public class AsyncServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {long start = System.currentTimeMillis();// 开启异步操作AsyncContext asyncContext = request.startAsync();// 开启线程操作CompletableFuture.runAsync(() -> {// 获取异步上下文中的 request 和 responsedoSomething(asyncContext.getRequest(), asyncContext.getResponse());});System.out.println("Async servlet: " + (System.currentTimeMillis() - start));}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}private void doSomething(ServletRequest request, ServletResponse response) {try {// 模拟耗时操作TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}try {response.getWriter().append("SyncServlet done");} catch (IOException e) {e.printStackTrace();}// 业务处理完成,通知结束request.getAsyncContext().complete();}}
结论
同步 Servlet 耗时:5007 毫秒,异步 Servlet 耗时:6 毫秒,浏览器响应都是 5000+ 毫秒,那么我们可以得出结论
- 无论是同步还是异步,对于前端浏览器来说,都是需要花费同样的等待时间
- 同步 Servlet 阻塞的是 tomcat 启动的线程
- 异步 Servlet 是非阻塞的,可以立即释放 tomcat 线程,去处理其他请求(大大增加了系统处理并发的能力)
- 如何开启异步 Servlet?
- 开启异步 Servlet 支持:
AsyncContext asyncContext = request.startAsync(); - 开启线程池执行业务代码
- 业务代码执行完毕后,调用异步上下文,通知结束:
asyncContext.complete()
- 开启异步 Servlet 支持:
