異步回調模式

異步回調

所謂異步回調,本質上就是多線程中線程的通信,如今很多業務系統中,某個業務或者功能調用多個外部接口,通常這種調用就是異步的調用。如何得到這些異步調用的結果自然也就很重要了。
Callable、Future、FutureTask

public class test implements Callable<Boolean>{public static void main(String[] args) {test a=new test();FutureTask futureTask=new FutureTask<>(a);new Thread(futureTask).start();Object su=null;try {su=futureTask.get();}catch (Exception e){e.printStackTrace();}System.out.println(su);}@Overridepublic Boolean call() throws Exception {return null;}
}

FutureTask和Callable都是泛型類,泛型參數表示返回結果的類型。通過FutureTask獲取異步線程的執行結果,但是其調用get()方法獲取異步結果時,主線程也會被阻塞。屬于異步阻塞模式。異步阻塞模式屬于主動模式的異步調用,異步回調屬于被動模式的異步調用。Java中回調模式的標準實現類為CompletableFuture。由于此類出現時間比較晚,期間Guava和Netty等都提出了自己的異步回調模式API來使用。這里主要介紹CompletableFuture,其他的有時間后面再學習。

CompletableFuture

在這里插入圖片描述
CompletableFuture實現Future和CompletionStage兩個接口。此類的實例作為一個異步任務,可以在自己異步執行完成之后觸發一些其他的異步任務,從而達到異步回調的效果。主要方法如下所示:

runAsync和supplyAsync創建子任務

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {return asyncSupplyStage(asyncPool, supplier);
}
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {return asyncSupplyStage(screenExecutor(executor), supplier);
}
public static CompletableFuture<Void> runAsync(Runnable runnable) {return asyncRunStage(asyncPool, runnable);
}
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) {return asyncRunStage(screenExecutor(executor), runnable);
}

可以看出runAsync沒有返回值,supplyAsync有返回值,此處用supplyAsync舉例:

ExecutorService executor= Executors.newFixedThreadPool(10);
CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{return "你好,周先生";
},executor);
System.out.println(completableFuture.get());//輸出你好,周先生
executor.shutdown();

上例中的線程池可以自己構造,如若不指定使用CompletableFuture中默認的線程池ForkJoinPool。
handle()方法統一處理異常和結果

//在執行任務的同一個線程中處理異常和結果
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) {return uniHandleStage(null, fn);
}
//可能不在執行任務的同一個線程中處理異常和結果
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) {return uniHandleStage(asyncPool, fn);
}
//在指定線程池executor中處理異常和結果
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {return uniHandleStage(screenExecutor(executor), fn);
}

案例:

CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{throw new RuntimeException("你好");
});
completableFuture.handle(new BiFunction<String,Throwable,String>(){@Overridepublic String apply(String s, Throwable throwable) {if(throwable==null){System.out.println("mei");;}else {System.out.println("出錯了");}return "ok";}
});

異步任務的串行執行

主要方法為以下幾種:thenApply()、thenAccept()、thenRun()和 thenCompose()。

thenApply()
此方法實現異步任務的串行化執行,前一個任務結果作為下一個任務的入參。

	后一個任務與前一個任務在同一個線程中執行public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {return uniApplyStage(null, fn);}//后一個任務與前一個任務不在同一個線程中執行public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) {return uniApplyStage(asyncPool, fn);}//后一個任務在指定的executor線程池中執行public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) {return uniApplyStage(screenExecutor(executor), fn);}

其中泛型參數T:上一個任務所返回結果的類型。泛型參數U:當前任務的返回類型。
案例:

		ExecutorService executor= Executors.newFixedThreadPool(10);CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,周先生";},executor).thenApplyAsync(new Function<String,String>() {@Overridepublic String apply(String s) {System.out.println(Thread.currentThread().getId());//13return "你好,毛先生";}});System.out.println(completableFuture.get());//輸出你好,毛先生executor.shutdown();

thenRun()
此方法不關心任務的處理結果。只要前一個任務執行完成,就開始執行后一個串行任務。而且沒有返回值。

	//后一個任務與前一個任務在同一個線程中執行public CompletableFuture<Void> thenRun(Runnable action) {return uniRunStage(null, action);}//后一個任務與前一個任務可以不在同一個線程中執行public CompletableFuture<Void> thenRunAsync(Runnable action) {return uniRunStage(asyncPool, action);}//后一個任務在executor線程池中執行public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor) {return uniRunStage(screenExecutor(executor), action);}

thenAccept()
使用此方法時一個任務可以接收(或消費)前一個任務的處理結果,但是后一個任務沒有結果輸出。

	//后一個任務與前一個任務在同一個線程中執行public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action) {return biAcceptStage(null, other, action);}//后一個任務與前一個任務不在同一個線程中執行public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action) {return biAcceptStage(asyncPool, other, action);}//后一個任務在指定的executor線程池中執行public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor) {return biAcceptStage(screenExecutor(executor), other, action);}

thenCompose()
對兩個任務進行串行的調度操作,第一個任務操作完成時,將其結果作為參數傳遞給第二個任務。

	//后一個任務與前一個任務在同一個線程中執行public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {return uniComposeStage(null, fn);}//后一個任務與前一個任務不在同一個線程中執行public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) {return uniComposeStage(asyncPool, fn);}//后一個任務在指定的executor線程池中執行public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,Executor executor) {return uniComposeStage(screenExecutor(executor), fn);}

thenCompose()方法第二個任務的返回值是一個CompletionStage異步實例。

		ExecutorService executor= Executors.newFixedThreadPool(10);CompletableFuture<String> completableFuture= CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,周先生";},executor).thenComposeAsync(new Function<String,CompletableFuture<String>>(){@Overridepublic CompletableFuture<String> apply(String s) {return CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,毛先生";});}});System.out.println(completableFuture.get());//輸出你好,毛先生executor.shutdown();

異步任務的合并執行

主要實現為以下幾個方法:thenCombine()、runAfterBoth()、
thenAcceptBoth()。

thenCombine()
thenCombine()會在兩個CompletionStage任務都執行完成后,一塊來處理兩個任務的執行結果。如果要合并多個任務,可以使用allOf()。

	//合并第二步任務的CompletionStage實例,返回第三步任務的CompletionStagepublic <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) {return biApplyStage(null, other, fn);}//不一定在同一個線程中執行第三步任務的CompletionStage實例public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) {return biApplyStage(asyncPool, other, fn);}//第三步任務的CompletionStage實例在指定的executor線程池中執行public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn, Executor executor) {return biApplyStage(screenExecutor(executor), other, fn);}

其中泛型參數T:表示第一個任務所返回結果的類型。泛型參數U:表示第二個任務所返回結果的類型。泛型參數V:表示第三個任務所返回結果的類型。
案例:

		CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,周先生";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,毛先生";});CompletableFuture<String> future3 = future1.thenCombine(future2, new BiFunction<String, String, String>(){@Overridepublic String apply(String s, String s2) {return s+"-----"+s2;}});String s = future3.get();System.out.println(s);//你好,周先生-----你好,毛先生

而runAfterBoth()方法不關注每一步任務的輸入參數和輸出參數,thenAcceptBoth()中第三個任務接收第一個和第二個任務的結果,但是不返回結果。

異步任務的選擇執行

若異步任務的選擇執行不是按照某種條件進行選擇的,而按照執行速度進行選擇的:前面兩并行任務,誰的結果返回速度快,其結果將作為第三步任務的輸入。對兩個異步任務的選擇可以通過CompletionStage接口的applyToEither()、acceptEither()等方法來實現。
applyToEither()

	//和其他任務進行速度比較,最快返回的結果用于執行fn回調函數public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) {return orApplyStage(null, other, fn);}//和其他任務進行速度比較,最快返回的結果用于執行fn回調函數,不一定在同一個線程中執行fn回調函數public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn) {return orApplyStage(asyncPool, other, fn);}//和其他任務進行速度比較,最快返回的結果用于執行fn回調函數,在指定線程池執行fn回調函數public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor) {return orApplyStage(screenExecutor(executor), other, fn);}

案例:

		CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}return "你好,周先生";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{System.out.println(Thread.currentThread().getId());//12return "你好,毛先生";});CompletableFuture<String> future3 = future1.applyToEither(future2, new Function<String, String>(){@Overridepublic String apply(String s) {return s;}});String s = future3.get();System.out.println(s);//你好,毛先生

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210125.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210125.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210125.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

半導體劃片機助力氧化鋁陶瓷片切割:科技與工藝的完美結合

在當今半導體制造領域&#xff0c;氧化鋁陶瓷片作為一種高性能、高可靠性的材料&#xff0c;被廣泛應用于各種電子設備中。而半導體劃片機的出現&#xff0c;則為氧化鋁陶瓷片的切割提供了新的解決方案&#xff0c;實現了科技與工藝的完美結合。 氧化鋁陶瓷片是一種以氧化鋁為基…

《巫師3》缺失vcomp110.dll如何解決,如何快速修復vcomp110.dll丟失問題

在日常使用電腦的過程中&#xff0c;我們可能會遇到一些錯誤提示&#xff0c;其中之一就是“vcomp110.dll丟失”。這個錯誤提示通常意味著vcomp110.dll文件在系統中無法找到或加載。那么&#xff0c;vcomp110.dll丟失的原因是什么&#xff1f;它對電腦有什么影響&#xff1f;本…

高德地圖vue實現自定義標點熱力圖效果(縮放時展示不同數據)

高德地圖插件引入省略。。。樣式和vue基礎組件省略。。。 如果每個標點沒有數值&#xff0c;則可以用點聚合來實現功能下面例子&#xff0c;每個標點會有按市統計的數值&#xff0c;而且縮放一定程度時&#xff0c;需要展示按省統計的標點&#xff0c;因此需要自定義標點樣式和…

leetcode刷題日志-54螺旋矩陣

思路&#xff1a; 上下左右設置四個邊界 每走完一行或者一列&#xff0c;移動相應邊界&#xff0c;當左邊界大于右邊界&#xff0c;或者上邊界大于下邊界時&#xff0c;結束 代碼如下&#xff1a; class Solution {public List<Integer> spiralOrder(int[][] matrix) {…

線程上下文切換

線程上下文切換 巧妙地利用了時間片輪轉的方式, CPU 給每個任務都服務一定的時間&#xff0c;然后把當前任務的狀態保存下來&#xff0c;在加載下一任務的狀態后&#xff0c;繼續服務下一任務&#xff0c;任務的狀態保存及再加載, 這段過程就叫做上下文切換。時間片輪轉的方式…

Determining Which Version of GDS is Installed

Determining Which Version of GDS is Installed To determine which version of GDS you have, run the following command: $ gdscheck.py -v Example output: GDS release version: 1.0.0.78 nvidia_fs version: 2.7 libcufile version: 2.4

冒泡排序和直接選擇排序(C/C++實現)

文章目錄 冒泡排序(交換排序&#xff09;基本思想特性總結代碼實現 直接選擇排序基本思想特性總結代碼實現&#xff08;優化&#xff0c;每次循環同時選擇最小和最大的數&#xff09; 冒泡排序(交換排序&#xff09; 基本思想 基本思想&#xff1a;所謂交換&#xff0c;就是根…

class065 A星、Floyd、Bellman-Ford與SPFA【算法】

class065 A星、Floyd、Bellman-Ford與SPFA【算法】 2023-12-9 19:27:02 算法講解065【必備】A星、Floyd、Bellman-Ford與SPFA code1 A*算法模版 // A*算法模版&#xff08;對數器驗證&#xff09; package class065;import java.util.PriorityQueue;// A*算法模版&#xff…

vue3+TypeScript全局事件總線mitt

在vue3中 $ on&#xff0c;$off 和 $once 實例方法已被移除&#xff0c;組件實例不再實現事件觸發接口&#xff0c;因此大家熟悉的EventBus便無法使用了。然而我們習慣了使用EventBus&#xff0c;對于這種情況我們可以使用Mitt庫 npm i mitt -S 首先要在全局掛載 mitt 在app…

兩年外包生涯做完,感覺自己廢了一半。。。。。

先說一下自己的情況&#xff0c;本科生&#xff0c;19年通過校招進入南京某軟件公司&#xff0c;干了接近2年的功能測試&#xff0c;今年年初&#xff0c;感覺自己不能夠在這樣下去了&#xff0c;長時間呆在一個舒適的環境會讓一個人墮落!而我已經在一個企業干了2年的功能測試&…

laravel的ORM 對象關系映射

Laravel 中的 ORM&#xff08;Eloquent ORM&#xff09;是 Laravel 框架內置的一種對象關系映射系統&#xff0c;用于在 PHP 應用中與數據庫進行交互。Eloquent 提供了一種優雅而直觀的語法&#xff0c;使得開發者可以使用面向對象的方式進行數據庫查詢和操作。 定義模型&…

結合ColorUI組件開發微信小程序

1.自定義組件生命周期函數&#xff1a; Component({data: {},attached() {console.log("自定義組件生命周期函數 attached--先執行");this.getPos();},ready() {console.log("ready生命周期函數---在attached之后執行")},methods: {getPos() {var that th…

數據結構:位圖、布隆過濾器以及海量數據面試題

位圖、布隆過濾器以及海量數據面試題 1.位圖1.1概念1.2實現1.3位圖應用 2.布隆過濾器2.1布隆過濾器的提出2.2布隆過濾器的概念2.3布隆過濾器的查找2.4布隆過濾器的實現2.5布隆過濾器的刪除2.6布隆過濾器的優點2.7布隆過濾器的缺點 3.海量數據面試題3.1哈希切分3.2位圖應用3.3布…

如何成為前1%的程序員

如果你想成為前1%的程序員&#xff0c;你必須遵循1%的程序員做什么&#xff0c;了解其他99%的人不做什么。在現代&#xff0c;我們有各種學習平臺&#xff0c;里面充滿了與編程相關的視頻、圖文以及其他資料。 舉例來說&#xff0c;我作為編程的初學者&#xff0c;去尋找路線圖…

IDEA2023找不到add framework support怎么解決

問題: 我的idea版本是2023.01&#xff0c;新版idea右鍵項目沒有Add Framework Support&#xff0c;help里面也找不到相關的。 從project structue的facets里面添加就行了&#xff0c;都是一樣的。 1.依舊是新建一個項目 2.file-->project structure--->facets 左上角加…

數據結構與程序的關系

在計算機科學中,數據結構和算法是兩個核心的概念。數據結構是程序的基礎,它組織和存儲數據的方式直接影響程序的設計、效率、可讀性以及程序的錯誤檢測和調試。本文將詳細討論數據結構如何影響程序,以及數據結構與算法的組合如何使程序更高效、可靠。 一、數據結構的選擇影…

Android studio如何安裝ai輔助工具

引言 在沒有翻墻的情況下&#xff0c;即單純在公司打工&#xff0c;經測試&#xff0c;大部分ai工具都是使用不了的&#xff08;比如各種gpt,codeium,copilot&#xff09;&#xff0c;根本登錄不了賬號&#xff0c;但有一個國內的codegeex是可以使用的&#xff0c;在這里不對各…

tensorflow中張量tensor

在 TensorFlow 中&#xff0c;主要操作的對象是張量&#xff08;tf.Tensor&#xff09;。張量表示一個多維數組&#xff0c;可以執行各種操作以構建和修改計算圖。以下是一些常見的 TensorFlow 張量操作&#xff1a; 1. 創建張量&#xff1a; 使用 tf.constant 創建常量張量。…

Android app性能優化指南

Android應用性能優化指南 提高應用程序的性能以實現更流暢的用戶體驗和更高的可見度。 性能在任何應用程序的成功中發揮著重要的作用。為用戶提供流暢無縫的體驗應該是開發人員的重點。 應用程序大小 在用戶開始使用我們的應用程序之前&#xff0c;他們需要下載應用程序并將…

DTCC2023大會-DBdoctor-基于eBPF觀測數據庫-附所有PPT下載鏈接

DTCC2023大會-DBdoctor-基于eBPF觀測數據庫-附所有PPT下載鏈接 8月16日—18日,第14屆中國數據庫技術大會(DTCC-2023)在北京國際會議中心舉行。聚好看在大會上首次發布基于eBPF觀測數據庫性能的產品DBdoctor&#xff0c;受到了業界廣泛的關注。近期幾位業內同仁過來要大會的PPT…