我們這一篇介紹一下java8中的異步編程,其實在java5的時候,F(xiàn)uture就已經(jīng)被引入了,下面我們用一個例子說明下Future的簡單使用,
public class FutureExample {
public static void main(String[] arg) throws ExecutionException, InterruptedException, TimeoutException {
ExecutorService executorService = new ThreadPoolExecutor(2,10,30, TimeUnit.MINUTES,new ArrayBlockingQueue<>(10));
Future<Integer> result = executorService.submit(() -> doSomething());
System.out.println(result.get(10,TimeUnit.SECONDS));
}
public static Integer doSomething() throws InterruptedException {
TimeUnit.SECONDS.sleep(7);//模擬時間占用
return 666;
}}
這邊我們使用了future來異步獲得返回值,那我們考慮一下,如果我們現(xiàn)在有多個任務(wù),任務(wù)之間還存在依賴關(guān)系的話,那么我們采用Future實現(xiàn),代碼是怎么樣的呢,我們難免要使用Future提供給我們的isDone來判斷,這樣代碼就會變得不簡潔,接下來我們就引入一個新的類,CompleteFuture 來解決future不能解決的復(fù)雜需求.
我們這邊假設(shè)這樣一個場景,收銀員使用一套系統(tǒng)來獲取輸入的水果的打折之后的價格,按照一般的代碼寫法:
public void delay() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
}
/**
* get the product price in synchronized way
*
* @param product
* @return
* @throws InterruptedException
*/
public double getPrice(String product) throws InterruptedException {
return calculatePrice(product);
}
/**
* calculate the price.
*
* @param price
* @return
* @throws InterruptedException
*/
public double calculatePrice(String price) throws InterruptedException {
delay();//模擬數(shù)據(jù)庫等操作
return new Random(100).nextDouble() * 100;//模擬價格
}
/**
* get the latest discount info
*
* @param product
* @return
*/
public double getLatestDiscountInfo(String product) throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
return new Random(100).nextDouble();
}
那我們?nèi)绾问褂肅ompleteFuture來進(jìn)行改造呢,看下面
public CompletableFuture<Double> getPriceAsync(String product) {
CompletableFuture<Double> futureResult = new CompletableFuture<>();
new Thread(() -> {
try {
double price = calculatePrice(product);
futureResult.complete(price);
} catch (InterruptedException e) {
futureResult.completeExceptionally(e);
}
}).start();
return futureResult;
}
看了一下這代碼,感覺有點雜,單獨(dú)開啟一個線程來,如果請求很多,那么大量的線程將占用大量的資源,一種解決的辦法是采用我們自己手工創(chuàng)建的線程池的方法,還有一種就是采用CompleteFuture給我們提供的靜態(tài)方法,如下 :
/**
* Returns a new CompletableFuture that is asynchronously completed
* by a task running in the given executor with the value obtained
* by calling the given Supplier.
*
* @param supplier a function returning the value to be used
* to complete the returned CompletableFuture
* @param executor the executor to use for asynchronous execution
* @param <U> the function's return type
* @return the new CompletableFuture
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
改造之后:
public CompletableFuture<Double> getPriceAsync(String product) {
//we can refactor above code to below
CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
Double v = null;
try {
v = calculatePrice(product);
} catch (InterruptedException e) {
e.printStackTrace();
}
return v;
}, threadExecutor);
return future;
}
再深入CompleteFuture, 我們觀察到其內(nèi)部還提供這些函數(shù)。

Screen Shot 2019-04-10 at 11.17.01 PM.png
我們可以猜測到,其功能可能遠(yuǎn)遠(yuǎn)不止我們上面介紹的那些,下面我們就簡單的使用下其中一個方法。
public static void testCombine() throws ExecutionException,InterruptedException {
PriceService priceService = new PriceService();
Future<Double> future = CompletableFuture.supplyAsync(() -> {
return priceService.getPrice("apple");
}).thenCombine(CompletableFuture.supplyAsync(() -> {
return priceService.getPrice("Grape");
}
), (priceOne, priceTwo) -> priceOne + priceTwo);
System.out.println("The sum of the price of apple and Grade is" + future.get());
}