一.前言
正常的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.異步請求是通過容器線程和程序線程的分配來提高效率。