CompletableFuture異步編程

CompletableFuture 有什麼用

  • CompletableFuture是用來描述多線程任務的時序關係的:串行關係,並行關係,聚合關係。java

  • CompletableFuture 是Java 8 新增長的Api,該類實現,Future和CompletionStage兩個接口,提供了很是強大的Future的擴展功能,能夠幫助咱們簡化異步編程的複雜性,提供了函數式編程的能力,能夠經過回調的方式處理計算結果,而且提供了轉換和組合CompletableFuture的方法。編程

建立CompletableFuture對象

方式一:使用默認線程池多線程

/**
 * 建立一個不帶返回值得任務。
 */
CompletableFuture<Void> f1 = CompletableFuture.runAsync(new Runnable() {
     @Override
     public void run() {
      //業務邏輯          
     }
 });
 /**
  * 建立一個帶返回值的任務。
  */
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        //業務邏輯
        return null;
    }
});

方式二:使用自定義線程池(建議使用)app

//建立線程池
ExecutorService	executor =	Executors.newFixedThreadPool(10); 
        
//建立一個不帶返回值得任務。
CompletableFuture<Void> f1 = CompletableFuture.runAsync(new Runnable() {
    @Override
    public void run() {

    }
},executor);
//建立一個帶返回值的任務。
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        //業務邏輯
        return null;
    }
},executor);
  1. 默認狀況下CompletableFuture會使用公共的ForkJoinPool線程池,這個線程池默認建立的線程數是CPU的 核數(也能夠經過JVM option:-Djava.util.concurrent.ForkJoinPool.common.parallelism來設置ForkJoinPool 線程池的線程數)。若是全部CompletableFuture共享一個線程池,那麼一旦有任務執行一些很慢的I/O操 做,就會致使線程池中全部線程都阻塞在I/O操做上,從而形成線程飢餓,進而影響整個系統的性能。因此,強烈建議你要根據不一樣的業務類型建立不一樣的線程池,以免互相干擾。
  2. 建立完CompletableFuture對象以後,會自動地異步執行runnable.run()方法或者supplier.get()方法。由於CompletableFuture類實現了Future接口,因此這兩個問題你均可以經過Future接口來解決。另外,CompletableFuture類還實現了CompletionStage接口。

經常使用API

  • public T get():獲取計算結果, 該方法爲阻塞方法會等待計算結果完成。
  • public T get(long timeout,TimeUnit unit):有時間限制的阻塞方法
  • public T getNow(T valueIfAbsent)當即獲取方法結果,若是沒有計算結束則返回傳的值
  • public T join()和 get() 方法相似也是主動阻塞線程,等待計算結果。和get() 方法有細微的差異。
  • public boolean complete(T value):當即完成計算,並把結果設置爲傳的值,返回是否設置成功
  • public boolean completeExceptionally(Throwable ex):當即完成計算,並拋出異常

理解CompletionStage接口

CompletionStage接口能夠清晰地描述任務之間的這種時序關係,時序關係:串行,並行,匯聚。dom

串行

線程與線程之間的執行順序是串行的。異步

//Async表明的是異步執行fn
CompletionStage<R>	thenApply(fn); 
CompletionStage<R>	thenApplyAsync(fn); 
CompletionStage<Void>	thenAccept(consumer); 
CompletionStage<Void>	thenAcceptAsync(consumer); 
CompletionStage<Void>	thenRun(action); 
CompletionStage<Void>	thenRunAsync(action); 
CompletionStage<R>	thenCompose(fn); 
CompletionStage<R>	thenComposeAsync(fn);
  • CompletionStage接口裏面描述串行關係,主要是thenApply、thenAccept、thenRun和thenCompose這四 個系列的接口。
    • thenApply系列函數裏參數fn的類型是接口Function<T, R>,這個接口裏與CompletionStage相關的方法是 R apply(T t),這個方法既能接收參數也支持返回值,因此thenApply系列方法返回的 是CompletionStage<R>。
  • 而thenAccept系列方法裏參數consumer的類型是接口Consumer<T>,這個接口裏與CompletionStage相關 的方法是 void accept(T t),這個方法雖然支持參數,但卻不支持回值,因此thenAccept系列方法返回 的是CompletionStage<Void>。
    • thenRun系列方法裏action的參數是Runnable,因此action既不能接收參數也不支持返回值,因此thenRun 系列方法返回的也是CompletionStage<Void>。
    • 這些方法裏面Async表明的是異步執行fn、consumer或者action。其中,須要你注意的是thenCompose系列 方法,這個系列的方法會新建立出一個子流程,最終結果和thenApply系列是相同的。

演示串行ide

//supplyAsync()啓動一個異步 流程
CompletableFuture<String> f0 = CompletableFuture.supplyAsync(
    () -> "Hello World")						//①		
    .thenApply(s ->	s + "girl")		//②
    .thenApply(String::toUpperCase);//③
System.out.println(f0.join());
//輸出結果 HELLO WORLD	girl

雖然這是一個異步流程,但任務①②③倒是 串行執行的,②依賴①的執行結果,③依賴②的執行結果。函數式編程

AND匯聚

CompletionStage接口裏面描述AND匯聚關係,主要是thenCombine、thenAcceptBoth和runAfterBoth系列的接口,這些接口的區別也是源自fn、consumer、action這三個核心參數不一樣。異步編程

CompletionStage<R>	thenCombine(other,	fn); 
CompletionStage<R>	thenCombineAsync(other,	fn); 
CompletionStage<Void>	thenAcceptBoth(other,	consumer); CompletionStage<Void>	thenAcceptBothAsync(other,	consumer); CompletionStage<Void>	runAfterBoth(other,	action); 
CompletionStage<Void>	runAfterBothAsync(other,	action);

演示:函數

// 啓動一個異步流程f1
        CompletableFuture<Void> f1 = CompletableFuture.runAsync(()->{
            System.out.println("異步任務-1");

        });
        // 啓動一個異步流程f2
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(()->{
            String s = "異步任務-2";
            System.out.println(s);
            return	s;

        });
        //啓動一個匯聚流程f3
        CompletableFuture<String> f3 = f1.thenCombine(f2,(a,tf)->{
            return tf;//tf是f2的值
        });

        //等待任務3執行結果
        System.out.println(f3.join());
OR匯聚

CompletionStage接口裏面描述OR匯聚關係,主要是applyToEither、acceptEither和runAfterEither系列的 接口,這些接口的區別也是源自fn、consumer、action這三個核心參數不一樣。

CompletionStage	applyToEither(other,	fn);
CompletionStage	applyToEitherAsync(other,	fn);
CompletionStage	acceptEither(other,	consumer);
CompletionStage	acceptEitherAsync(other,	consumer);
CompletionStage	runAfterEither(other,	action); 
CompletionStage	runAfterEitherAsync(other,	action);

功能演示:

// 啓動一個異步流程f1
        CompletableFuture<String> f1 = CompletableFuture.supplyAsync(()->{
            int	t	=	 new Random().nextInt(10);
            System.out.println("f1-t = "+t);
            sleep(t,	TimeUnit.SECONDS);
            return	String.valueOf(t);
        });
	 // 啓動一個異步流程f2
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(()->{
            int	t	=	 new Random().nextInt(10);
            System.out.println("f2-t = "+t);
            sleep(t,	TimeUnit.SECONDS);
            return	String.valueOf(t);
        });
		//將f1和f2的值彙總到f3
        CompletableFuture<String> f3 = f1.applyToEither(f2,s	->
                    Integer.parseInt(f2.join())+Integer.parseInt(s)+""
        );
        System.out.println(f3.join());

**** 碼字不易若是對你有幫助請給個關注****

**** 愛技術愛生活 QQ羣: 894109590****

相關文章
相關標籤/搜索