說異步調用
前,咱們說說它對應的同步調用
。一般開發過程當中,通常上咱們都是同步調用
,即:程序按定義的順序依次執行的過程,每一行代碼執行過程必須等待上一行代碼執行完畢後才執行。而異步調用
指:程序在執行時,無需等待執行的返回值可繼續執行後面的代碼。顯而易見,同步有依賴相關性,而異步沒有,因此異步可併發
執行,可提升執行效率,在相同的時間作更多的事情。html
回調:處理異步
、同步
外,還有一個叫回調
。其主要是解決異步方法執行結果的處理方法,好比在但願異步調用結束時返回執行結果,這個時候就能夠考慮使用回調機制。前端
在編寫實際代碼以前,咱們來了解下一些關於異步請求的api的調用說明。java
HttpServletRequest
對象獲取。
1
|
AsyncContext asyncContext = request.startAsync();
|
其監聽器的接口代碼:web
1
2
3
4
5
6
|
public
interface
AsyncListener
extends
EventListener {
void
onComplete(AsyncEvent event)
throws
IOException;
void
onTimeout(AsyncEvent event)
throws
IOException;
void
onError(AsyncEvent event)
throws
IOException;
void
onStartAsync(AsyncEvent event)
throws
IOException;
}
|
說明:spring
通常上,咱們在超時或者異常時,會返回給前端相應的提示,好比說超時了,請再次請求等等,根據各業務進行自定義返回。同時,在異步調用完成時,通常須要執行一些清理工做或者其餘相關操做。api
須要注意的是隻有在調用request.startAsync
前將監聽器添加到AsyncContext
,監聽器的onStartAsync
方法纔會起做用,而調用startAsync
前AsyncContext
還不存在,因此第一次調用startAsync
是不會被監聽器中的onStartAsync
方法捕獲的,只有在超時後又從新開始的狀況下onStartAsync
方法纔會起做用。併發
setTimeout
方法設置,單位:毫秒。必定要設置超時時間,不能無限等待下去,否則和正常的請求就同樣了。。app
package com.example.demo.Servlet; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 使用Servlet方式進行異步請求 */ @Slf4j @RestController public class ServletController { @RequestMapping(value = "/servlet/orig") public void todo(HttpServletRequest request, HttpServletResponse response) throws InterruptedException, IOException { response.setContentType("ext/html;charset=UTF-8"); Thread.sleep(1000); response.getWriter().print("這是【正常】的請求返回"); } @RequestMapping(value = "/servlet/async") public void todoAsync(HttpServletRequest request, HttpServletResponse response) { AsyncContext asyncContext = request.startAsync(); asyncContext.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent asyncEvent) throws IOException { log.info("執行完成"); } @Override public void onTimeout(AsyncEvent asyncEvent) throws IOException { log.info("超時了"); } @Override public void onError(AsyncEvent asyncEvent) throws IOException { log.info("發生錯誤"); } @Override public void onStartAsync(AsyncEvent asyncEvent) throws IOException { log.info("線程開始"); } }); asyncContext.setTimeout(20000); asyncContext.start(() -> { try { Thread.sleep(10000); System.out.println("ddddd"); log.info("內部線程:"+Thread.currentThread().getName()); asyncContext.getResponse().setCharacterEncoding("utf-8"); asyncContext.getResponse().setContentType("text/html;charset=UTF-8"); asyncContext.getResponse().getWriter().print("這是【異步】的請求返回"); }catch (Exception e){ log.error("異常",e); } //異步請求完成通知 //此時整個請求才完成 //其實能夠利用此特性 進行多條消息的推送 把鏈接掛起。。 asyncContext.complete(); }); System.out.println("main方法線程"); //此時之類 request的線程鏈接已經釋放了 log.info("線程:" + Thread.currentThread().getName()); } }
注意:異步請求時,能夠利用ThreadPoolExecutor
自定義個線程池。異步
1.啓動下應用,查看控制檯輸出就能夠獲悉是否在同一個線程裏面了。同時,可設置下等待時間,以後就會調用超時回調方法了。你們可本身試試。async