在Servlet3.0之前,Servlet采用Thread-Per-Request的方式处理请求
即每次Http请求都有一个线程从头到尾负责处理
如果一个请求需要进行IO操作,比如访问数据库、调用第三方服务接口等,那么其所对应的线程将同步地等待IO操作完成,而IO操作是非常慢的,所以此时的线程不能及时的释放回线城市以供后续使用,在并发量越来越大的情况下,这将带来严重的性能问题。即便是像Spring这样的高层框架也脱离不了这样的束缚。因为他们都是建立在servlet之上的。为了解决这样的问题,Servlet3.0引入了异步处理,然后在Servlet3.1中又引入了非阻塞IO来进一步增强异步处理的性能。
同步的例子:
@WebServlet("/hello") public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println(Thread.currentThread()+"start..."); try { sayHello(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } resp.getWriter().write("hello"); System.out.println(Thread.currentThread()+"end..."); } public void sayHello() throws InterruptedException { System.out.println(Thread.currentThread()+"processing..."); Thread.sleep(3000); } }
请求之后:
开启异步:
@WebServlet(value = "/async", asyncSupported = true) // true 就可以支持异步了 public class HelloAsyncServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("主线程...."+Thread.currentThread()); AsyncContext startAsync = req.startAsync(); // 业务逻辑进行异步处理;开启异步处理 startAsync.start(new Runnable() { @Override public void run() { try { System.out.println("副线程开启...."+Thread.currentThread()+Thread.currentThread()+"==>"+System.currentTimeMillis()); sayHello(); //获取到异步的上下文 AsyncContext asyncContext = req.getAsyncContext(); // 获取响应 ServletResponse response = asyncContext.getResponse(); //获取交出去的响应 response.getWriter().write("hello toov5 async"); startAsync.complete(); //异步调用完毕 开始给予响应 System.out.println("副线程结束...."+Thread.currentThread()+"==>"+System.currentTimeMillis()); } catch (InterruptedException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); System.out.println("主线程结束..."+Thread.currentThread()+"==>"+System.currentTimeMillis()); } public void sayHello() throws InterruptedException { System.out.println(Thread.currentThread() + "processing..."); Thread.sleep(3000); } }
结果:
如果开启了异步处理 当前tomcat线程池里的线程立马结束,交给新的异步处理的线程池中的线程去处理
当前这个没有去维护异步处理的线程池。
springmvc 会维护一个异步处理的线程池
这样主线程释放 等待下一个请求