为什么要使用异步 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 和 response
doSomething(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 支持: