SpringBoot中异步请求的使用
一.前言
正常的http请求是由一个线程从头到尾来处理,当如果有请求耗时过长,而我们容器的线程数量是有限的,但所有线程都在使用,就会造成新的请求无法进行。
异步请求可以实现当http请求进入到程序,可以先释放容器的线程,由程序内部的线程进行处理,等处理完成后,再调回容器的线程来返回请求结果。这就可以在一定程度上提高系统的吞吐量。
二.实现
1.使用Servlet方法来实现
@RequestMapping(value = "/importData", method = RequestMethod.POST) public void importData(HttpServletRequest request) { AsyncContext asyncContext = request.startAsync(); //设置监听器:可设置其开始、完成、异常、超时等事件的回调处理 asyncContext.addListener(new AsyncListener() { @Override public void onTimeout(AsyncEvent event) throws IOException { System.out.println("超时了..."); //做一些超时后的相关操作... } @Override public void onStartAsync(AsyncEvent event) throws IOException { System.out.println("线程开始"); } @Override public void onError(AsyncEvent event) throws IOException { System.out.println("发生错误:"+event.getThrowable()); } @Override public void onComplete(AsyncEvent event) throws IOException { System.out.println("执行完成"); //这里可以做一些清理资源的操作... } }); //设置超时时间 asyncContext.setTimeout(3000000);//5分钟 asyncContext.start(() -> { Result rm = new Result(); try { System.out.println("内部线程:" + Thread.currentThread().getName()); asyncContext.getResponse().setCharacterEncoding("utf-8"); asyncContext.getResponse().setContentType("text/html;charset=UTF-8"); asyncContext.getResponse().getWriter().println("返回成功"); } catch (Exception e) { System.out.println("异常:" + e); } //异步请求完成通知 //此时整个请求才完成 asyncContext.complete(); }); //此时之类 request的线程连接已经释放了 System.out.println("主线程:" + Thread.currentThread().getName()); }
2.在SpringBoot中可以使用Callable、DeferredResult、WebAysncTask。这里只举Callable的代码例子。
@RequestMapping("/callable") public Callable<String> callable() { log.info("外部线程:" + Thread.currentThread().getName()); return new Callable<String>() { @Override public String call() throws Exception { log.info("内部线程:" + Thread.currentThread().getName()); return "callable!"; } }; }
三.总结
1.异步请求可以有效提供系统的吞吐量。
2.异步请求是通过容器线程和程序线程的分配来提高效率。