1. 程式人生 > >用個小例子來介紹一下JDK8的CompletableFuture

用個小例子來介紹一下JDK8的CompletableFuture

程式碼要解決的問題是:在兩個執行緒裡並行執行任務A和任務B,只要有一個任務完成了,就執行任務C。程式碼如下:

import java.time.LocalTime;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class LearnCompleteFuture {
	
	private static Random random = new Random();

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		useFuture();
		
		TimeUnit.SECONDS.sleep(10);
		System.out.println();
		
		useCompletableFuture();
	}

	private static void useFuture() throws InterruptedException, ExecutionException {
		System.out.println("Future");
		ExecutorService exector = Executors.newFixedThreadPool(3);
		Future<Void> futureA = exector.submit(() -> work("A1"));
		Future<Void> futureB = exector.submit(() -> work("B1"));
		while (true) {
			try {
				futureA.get(1, TimeUnit.SECONDS);
				break;
			} catch (TimeoutException e) {
			}
			try {
				futureB.get(1, TimeUnit.SECONDS);
				break;
			} catch (TimeoutException e) {
			}
		}
		exector.submit(() -> work("C1")).get();
		exector.shutdown();
	}
	
	private static void useCompletableFuture() throws InterruptedException, ExecutionException {
		System.out.println("CompletableFuture");
		CompletableFuture<Void> futureA = CompletableFuture.runAsync(() -> work("A2"));
		CompletableFuture<Void> futureB = CompletableFuture.runAsync(() -> work("B2"));
		futureA.runAfterEither(futureB, () -> work("C2")).get();
	}

	public static Void work(String name) {
		System.out.println(name + " starts at " + LocalTime.now());
		try {
			TimeUnit.SECONDS.sleep(random.nextInt(10));
		} catch (InterruptedException e) {
		}
		System.out.println(name + " ends at " + LocalTime.now());
		return null;
	}
}

兩種方法useFuture和useCompletableFuture相比:

首先,方法2 比 方法1 的程式碼簡單。在方法1裡,既要自己照顧執行緒池的建立和銷燬,還要負責對任務A和任務B的監控。而方法2,只需要用CompletableFuture的runAfterEither就完成了任務A、任務B和任務C之間的依賴關係的定義。

在方法2,甚至用一行程式碼就能完成:

CompletableFuture.runAsync(() -> work("A2")).runAfterEither(CompletableFuture.runAsync(() -> work("B2")), () -> work("C2")).get();


其次,方法2 比 方法1 高效。

方法1的主執行緒,要通過while(true)的方式不斷地輪詢任務A和任務B的執行狀況,浪費CPU資源,而方法2的主執行緒只需要在最後的get()上靜靜地等待任務C的完成。

下面是程式執行的輸出:


從方法1的輸出可以看出,任務C1的開始並不是緊隨著任務A1的完成,差了0.971秒,原因是在方法1裡,是對任務A1和任務B1都用get(1)來詢問他們的狀態,當其中一個任務先完成時,主執行緒可能正阻塞在另一個未完成任務的get上

而方法2完全不存在這樣的問題,任務C2的開始於任務A1的結束之間沒有任何的時間差。

有關CompletableFuture和CompletionStage,同學們應該去翻翻他們的javadoc,他們是jdk8對Fork/Join框架非常重要的貢獻,充分利用能幫助你用簡潔的程式碼就能寫出高效靈活的併發演算法。

留下一個作業題,用CompletableFuture來模擬專案管理裡的甘特圖。

相關推薦

例子介紹一下JDK8的CompletableFuture

程式碼要解決的問題是:在兩個執行緒裡並行執行任務A和任務B,只要有一個任務完成了,就執行任務C。程式碼如下: import java.time.LocalTime; import java.util.Random; import java.util.concurrent.

M03 利用Accord 進行機器學習的第一例子

statistic decide blog cat studio mac eap strong cte 01 安裝 Visual studio 2017. 不具備安裝這個的話,也可安裝,Microsoft Visual Studio Express (or equiva

Sql行轉列的兩例子

SQL行轉列 所謂行轉列就是將某一個category型別的列(nx1的矩陣,實質是有m類),目標是將多行轉換成為多列(新增m列)。 例1:模擬順豐SQL小例子 ##順豐面試題(SQLite編碼實現題目) import sqlite3 conn=sqlite3.con

多態的兩例子

getclass ava stat new 隱式 static return 應該 多態 class A { public String show(B obj){ return ("A and D"); } public String

RabbitMQ及其.NET客戶端——幾例子

一、簡單生產者-消費者(使用direct交換器) 1、生產者   var factory = new ConnectionFactory();//例項化一個工廠 factory.HostName = "localhost"; factory.UserName = "honnnnl";

mysql是我們專案中非常常用的資料型資料庫。但是因為我們需要在資料庫儲存中文字元,所以經常遇到資料庫亂碼情況。下面就介紹一下如何徹底解決資料庫中文亂碼情況。

mysql是我們專案中非常常用的資料型資料庫。但是因為我們需要在資料庫儲存中文字元,所以經常遇到資料庫亂碼情況。下面就來介紹一下如何徹底解決資料庫中文亂碼情況。 1、中文亂碼 1.1、中文亂碼 create table user(name varchar(11)); # 建立user表

什麼是量子計算機?一個簡單例子解釋

譯者:王亮 作者:YK Sugi 原文:http://t.cn/EZAElk0 Hi,大家好! 不久前,我參觀了加拿大溫哥華的D-Wave Systems公司,這是一家制造前沿量子計算機的公司。 我在那裡學到了很多關於量子計算機的知識,所以我寫這篇文章來和大家分享我在那裡所學到的一些知識。

學習c++多型的幾例子

//reference: http://blog.csdn.net/hackbuteer1/article/details/7475622 #include<iostream> #include<string> #include <vect

python的迴圈——幾例子

1、整數序列求和。使用者輸入一個正整數N,計算從1到N(包含1和N)相加之後的結果。          2、九九乘法表輸出。          3、階乘計算。計算1+2!+3!+……10!的結果         4、健康食譜輸出。列出5種不同的食材,請輸出他們可能組成的所

從一個例子初步認識遞迴,迭代,動態規劃。

問題:有n步臺階,一次只能上1步或者2步,共有多少種走法? 思路: a 遞迴 步驟1:找到走完前n步臺階和前n-1步臺階之間的關係。 為了走上n步臺階,只有兩種方法:從n-1步臺階爬1步走到或從n-2步臺階處爬兩步走到。如果f(n)是爬到第n臺階的方法數,則f(n) = f

讓我們貨幣的眼光分析一下比特幣

'我們實際上建造了這個在過去二三百年我麼生活於其中的世界,我們犯下了一些錯誤,我們學習,為了讓世界變得更好,在我看來,那種觀點認為(比特幣)是金鑰匙,只要我們不再做一些事情,完美的秩序就將會出現,這種觀點是幼稚的,是思想上的迷惑,這在我看來,但是這並不是說比特幣不是一個令人興奮的東西,比特幣

工廠模式個人寫例子進行總結

工廠模式是我們最常用的例項化物件模式了,是用工廠方法代替new操作的一種模式。著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程式系統可以說是隨處可見。因為工廠模式就相當於建立例項物件的

使用Dagger2建立的第一例子

將Dagger系列的咖啡壺例子再做一下簡化,作為Dagger2的入門的第一個小例子。 場景描述:有一個電水壺,它使用一個加熱器來燒水。電水壺具備的功能有:開始加熱(on方法),結束加熱(off方法),倒水(brew方法)。 正確使用Dagger2要按照以下5個步驟來進行:

例子--memory leak

C++程式設計師最害怕、最容易遇到的問題就是記憶體洩露,或是說非法訪問記憶體。 不想說太多的道理,就用幾個簡單的例子來詮釋。 指標超過作用域 void MemoryLeak( ) { int

ruby+selenium-webdriver一步一步完成自動化測試-----第一例子

第一個小例子,登入soso首頁,簡單直觀易懂。通常我們都是這樣寫的,網上各種例子也是這樣的。 1.開啟文字編輯器SciTe2.file--new新建一個檔案,寫下如下程式碼 #encoding: utf-8 require 'rubygems' require 'sele

生動的例子解釋卷積

前言 學了幾周的深度學習,前幾天感覺基礎不太牢固,於是今天便從卷積神經網路開始複習,把腦子中不太清楚的概念全部弄清楚。先在這裡說清楚,本文大部分例子都是參考其他的部落格,在某些例子中有些許改動,穿插著我自己的理解。 1. 從捲毛巾開始理解卷積 首先看看卷積的定義

Java繼承的兩例子

首先上程式碼 public class A { protected String value = "123"; public A(){ System.out.println("A"); } public String get

Socket 單執行緒多使用者併發的兩例子

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include

試試 IEnumerable 的 10 例子

IEnumerable 介面是 C# 開發過程中非常重要的介面,對於其特性和用法的瞭解是十分必要的。本文將通過10個小例子,來熟悉一下其簡單的用法。 全是原始碼 以下便是這10個小例子,響應的說明均標記在註釋中。 每個以 TXX 開頭命名的均是一個示例。建議從上往下閱讀。 using System; usi

試試 IEnumerable 的另外 6 例子

IEnumerable 介面是 C# 開發過程中非常重要的介面,對於其特性和用法的瞭解是十分必要的。本文將通過6個小例子,來熟悉一