詳解java 三種呼叫機制(同步、回撥、非同步)
同步呼叫、回撥和非同步呼叫。
同步呼叫是一種阻塞式呼叫,呼叫方要等待對方執行完畢才返回,它是一種單向呼叫;
回撥是一種雙向呼叫模式,也就是說,被呼叫方在介面被呼叫時也會呼叫對方的介面;
具體說來:就是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。
僅僅用來學習,如有侵權,聯絡我,馬上刪除。
莫聽穿林打葉聲,何妨吟嘯且徐行!!!