为什么要使用异步 Servlet,同步 Servlet 阻塞了什么?异步 Servlet 是怎样工作的?

**

同步 Servlet

先看一个同步 Servlet 的 Demo,代码非常简单,就是模拟了一个 5s 耗时的操作,然后程序打印一段话,记录程序执行时间,通过允许这段代码,我们发现总耗时为:5007 毫秒

  1. @WebServlet(name="SyncServlet",urlPatterns="/SyncServlet")
  2. public class SyncServlet extends HttpServlet {
  3. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  4. long start = System.currentTimeMillis();
  5. doSomething(request, response);
  6. System.out.println("Sync servlet: " + (System.currentTimeMillis() - start));
  7. }
  8. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  9. doGet(request, response);
  10. }
  11. private void doSomething(HttpServletRequest request, HttpServletResponse response) {
  12. try {
  13. // 模拟耗时操作
  14. TimeUnit.SECONDS.sleep(5);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. try {
  19. response.getWriter().append("SyncServlet done");
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

异步 Servlet

相同的 Demo,我们启用了异步支持,通过测试,耗时:6 毫秒

  1. @WebServlet(name = "AsyncServlet", urlPatterns = "/AsyncServlet", asyncSupported = true)
  2. public class AsyncServlet extends HttpServlet {
  3. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  4. long start = System.currentTimeMillis();
  5. // 开启异步操作
  6. AsyncContext asyncContext = request.startAsync();
  7. // 开启线程操作
  8. CompletableFuture.runAsync(() -> {
  9. // 获取异步上下文中的 request 和 response
  10. doSomething(asyncContext.getRequest(), asyncContext.getResponse());
  11. });
  12. System.out.println("Async servlet: " + (System.currentTimeMillis() - start));
  13. }
  14. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  15. doGet(request, response);
  16. }
  17. private void doSomething(ServletRequest request, ServletResponse response) {
  18. try {
  19. // 模拟耗时操作
  20. TimeUnit.SECONDS.sleep(5);
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. try {
  25. response.getWriter().append("SyncServlet done");
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. // 业务处理完成,通知结束
  30. request.getAsyncContext().complete();
  31. }
  32. }

结论

同步 Servlet 耗时:5007 毫秒,异步 Servlet 耗时:6 毫秒,浏览器响应都是 5000+ 毫秒,那么我们可以得出结论

  • 无论是同步还是异步,对于前端浏览器来说,都是需要花费同样的等待时间
  • 同步 Servlet 阻塞的是 tomcat 启动的线程
  • 异步 Servlet 是非阻塞的,可以立即释放 tomcat 线程,去处理其他请求(大大增加了系统处理并发的能力)
  • 如何开启异步 Servlet?
    • 开启异步 Servlet 支持: AsyncContext asyncContext = request.startAsync();
    • 开启线程池执行业务代码
    • 业务代码执行完毕后,调用异步上下文,通知结束: asyncContext.complete()