同步調用、回調和異步調用。
同步調用是一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用;
回調是一種雙向調用模式,也就是說,被調用方在接口被調用時也會調用對方的接口;
具體說來:就是A類中調用B類中的某個方法C,然后B類中反過來調用A類中的方法D,D這個方法就叫回調方法,
異步調用是一種類似消息或事件的機制,不過它的調用方向剛好相反,接口的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的接口)。
多線程是異步處理,異步就意味着不知道處理結果。回調一般是異步處理的一種技術。
Future 半異步, 線程+callback 全異步, java8 CompletableFurute 異步回調鏈式編排。
同步回調
下面的例子去掉開啟多線程就是同步回調。
異步回調的使用
1、定義接口
public interface CallBack { public void solve(String result); }
2、主調程序
public class CallbackRequest implements Callback{ private CallbackResponse callbackResponse; public CallbackRequest(CallbackResponse callbackResponse) { this.callbackResponse = callbackResponse; } //主調需要解決一個問題,所以他把問題交給被調處理,被調單獨創建一個線程,不影響主調程序的運行 public void request(final String question){ System.out.println("主調程序問了一個問題"); new Thread(()->{ //B想要幫A處理東西,就必須知道誰讓自己處理的,所以要傳入a,也要知道a想處理什么,所以要傳入question callbackResponse.handler(this, question); }).start(); //A把要處理的事情交給b之后,就可以自己去玩耍了,或者去處理其他事情 afterAsk(); } private void afterAsk(){ System.out.println("主調程序繼續處理其他事情"); } @Override public void solve(String result) { System.out.println("被調程序接到答案后進行處理" + result); } }
3、被調程序:
public class CallbackResponse { public void handler(Callback callback, String request) { System.out.println(callback.getClass()+"問的問題是:"+ request); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } String result="\n答案是2"; callback.solve(result); } }
4、測試:
public class CallbackTest { public static void main(String[] args) { CallbackResponse callbackResponse = new CallbackResponse(); CallbackRequest callbackRequest = new CallbackRequest(callbackResponse); callbackRequest.request("1+1"); } } 輸出: 主調程序問了一個問題 主調程序繼續處理其他事情 class javapratice.CallbackRequest問的問題是:1+1 被調程序接到答案后進行處理 答案是2
一句話解釋回調:當前方法有一段邏輯,需要調用者來決定怎么執行。這段邏輯肯定不能寫死,所以需要一個接口,來解耦當前方法和調用者!
Java多線程中可以通過callable和future或futuretask結合來獲取線程執行后的返回值。實現方法是通過get方法來調用callable的call方法獲取返回值。
其實這種方法本質上不是回調,回調要求的是任務完成以后被調用者主動回調調用者的接口,而這里是調用者主動使用get方法阻塞獲取返回值。
Callable的使用
1、結合Callable和Future一起使用,通過ExecutorService的submit方法執行Callable,並返回Future。
ExecutorService executor = Executors.newCachedThreadPool();
Future<String> future = executor.submit(() ->
{ System.out.println("call"); TimeUnit.SECONDS.sleep(1); return "str"; } );
//手動阻塞調用get通過call方法獲得返回值。 System.out.println(future.get()); //需要手動關閉,不然線程池的線程會繼續執行。 executor.shutdown();
2、使用futuretask同時作為線程執行單元和數據請求單元
FutureTask<Integer> futureTask = new FutureTask(() ->
{ System.out.println("dasds"); return new Random().nextInt(); });
new Thread(futureTask).start(); //阻塞獲取返回值 System.out.println(futureTask.get());
注:比起future.get(),其實更推薦使用get (long timeout, TimeUnit unit)方法,設置了超時時間可以防止程序無限制的等待future的結果。
文章來自:https://www.cnblogs.com/liujiarui/p/13395424.html。
僅僅用來學習,如有侵權,聯系我,馬上刪除。