Servlet3.0的非同步支援-AsyncContext
阿新 • • 發佈:2018-12-11
Servlet3是Tomcat7出現的新特性,所以使用的tomcat版本不能低於7.0.
由於每個request請求進來之後都被分配了一個執行緒處理,如果當前處理的業務方法非常耗時,將會在某段時間出現非常多的執行緒,而其他請求無法被分配到執行緒執行而被拒絕,所以Servlet3.0引入了非同步支援,請求進來後交給另外一個工作執行緒去執行,釋放當前接入請求的執行緒,這樣就可以接入越來越多的請求,提高併發量。
if (request.isAsyncSupported()) { //用於啟動非同步工作執行緒,進入非同步模式,呼叫業務處理執行緒進行業務處理 request.startAsync(request, response); if (request.isAsyncStarted()) { /** * 1 獲取AsyncContext,對非同步執行的上下文提供支援,可以透過AsyncContext的getRequest() 、 getResponse()方法取得Request、Response物件 * 2 客戶端的響應將暫緩至,呼叫AsyncContext的complete()方法或dispatch()為止,前者表示迴應完成,後者表示將響應調派給指定的URL * 3 使用非同步處理方式,web容器的請求處理執行緒釋放了,可以服務其他的請求處理。但是該Request的處理並沒有結束, * 在使用AsyncContext的complete或者dispatch完成後,這個request的處理才結束。 * */ final AsyncContext asyncContext = request.getAsyncContext(); asyncContext.setTimeout(SysConfig.getInstance().getPropertyInt("async_timeout")); // Servlet不會被阻塞,而是直接往下執行 asyncContext.start( // 開啟http執行緒 new Runnable() { @Override public void run() { PrintWriter printWriter = null; try { logger.info("休眠3秒鐘..."); Thread.sleep(3000); String responseMsgContent = ""; String ws_callback = SysConfig.getInstance().getProperty("ws_callback"); String result = HttpUtils.postHttpAndHttps(ws_callback, "desc="+System.currentTimeMillis()+"-"+RandomUtils.nextInt(0, 9999)); logger.info("執行緒Name:{},result:{}",Thread.currentThread().getName(),result); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-type","application/json;charset=UTF-8"); printWriter = response.getWriter(); printWriter.write(responseMsgContent); logger.info(responseMsgContent); } catch (Exception e) { e.printStackTrace(); } finally { if (printWriter != null) { printWriter.flush(); printWriter.close(); } //告訴啟動非同步處理的Servlet非同步處理已完成,Servlet就會提交請求響應 asyncContext.complete(); } } }); logger.info("繼續執行...."); } } else { // 不支援非同步 logger.info("當前servlet容器不支援非同步...."); }
以上的asyncContext.start(new Runnable(){});這個方法是將任務提交給了主執行緒池,這樣的話感覺不過還是使用的主執行緒池的執行緒數,可能效果不是很好。
我們也可以使用自定義執行緒池,將需要非同步處理的任務提交給執行緒池管理,靈活呼叫。
package com.jeff.nio.controller; import java.io.PrintWriter; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.servlet.AsyncContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.jeff.nio.server.common.JsonDto; /** * 登入 * */ @Controller public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100)); @GetMapping(value="/servlet3.0/asyncContext") public @ResponseBody void startServer(HttpServletRequest request, HttpServletResponse response) { JsonDto jsonDto = new JsonDto(); try { logger.info("start server..................."); if (request.isAsyncSupported()) { //用於啟動非同步工作執行緒,進入非同步模式,呼叫業務處理執行緒進行業務處理 request.startAsync(request, response); if (request.isAsyncStarted()) { /** * 1 獲取AsyncContext,對非同步執行的上下文提供支援,可以透過AsyncContext的getRequest() 、 getResponse()方法取得Request、Response物件 * 2 客戶端的響應將暫緩至,呼叫AsyncContext的complete()方法或dispatch()為止,前者表示迴應完成,後者表示將響應調派給指定的URL * 3 使用非同步處理方式,web容器的請求處理執行緒釋放了,可以服務其他的請求處理。但是該Request的處理並沒有結束, * 在使用AsyncContext的complete或者dispatch完成後,這個request的處理才結束。 * */ final AsyncContext asyncContext = request.getAsyncContext(); asyncContext.setTimeout(5000); // Servlet不會被阻塞,而是直接往下執行 executor.execute(new Runnable() { @Override public void run() { PrintWriter printWriter = null; try { logger.info("休眠3秒鐘..."); Thread.sleep(3000); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-type","application/json;charset=UTF-8"); printWriter = response.getWriter(); printWriter.write(jsonDto.toString()); } catch (Exception e) { e.printStackTrace(); } finally { if (printWriter != null) { printWriter.flush(); printWriter.close(); } //告訴啟動非同步處理的Servlet非同步處理已完成,Servlet就會提交請求響應 asyncContext.complete(); } } }); logger.info("繼續執行...."); } } else { // 不支援非同步 logger.info("當前servlet容器不支援非同步...."); } } catch (Exception e) { e.printStackTrace(); jsonDto.setCode("-1"); jsonDto.setMsg("執行失敗"); } } }