您好,登錄后才能下訂單哦!
一. Future
JDK 5引入了Future模式。Future接口是Java多線程Future模式的實現,在java.util.concurrent包中,可以來進行異步計算。
Future模式是多線程設計常用的一種設計模式。Future模式可以理解成:我有一個任務,提交給了Future,Future替我完成這個任務。期間我自己可以去做任何想做的事情。一段時間之后,我就便可以從Future那兒取出結果。
Future的接口很簡單,只有五個方法。
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future接口的方法介紹如下:
一般情況下,我們會結合Callable和Future一起使用,通過ExecutorService的submit方法執行Callable,并返回Future。
ExecutorService executor = Executors.newCachedThreadPool(); Future<String> future = executor.submit(() -> { //Lambda 是一個 callable, 提交后便立即執行,這里返回的是 FutureTask 實例 System.out.println("running task"); Thread.sleep(10000); return "return task"; }); try { Thread.sleep(1000); } catch (InterruptedException e) { } System.out.println("do something else"); //前面的的 Callable 在其他線程中運行著,可以做一些其他的事情 try { System.out.println(future.get()); //等待 future 的執行結果,執行完畢之后打印出來 } catch (InterruptedException e) { } catch (ExecutionException e) { } finally { executor.shutdown(); }
比起future.get(),其實更推薦使用get (long timeout, TimeUnit unit) 方法,設置了超時時間可以防止程序無限制的等待future的結果。
二. CompletableFuture介紹
2.1 Future模式的缺點
Future雖然可以實現獲取異步執行結果的需求,但是它沒有提供通知的機制,我們無法得知Future什么時候完成。
要么使用阻塞,在future.get()的地方等待future返回的結果,這時又變成同步操作。要么使用isDone()輪詢地判斷Future是否完成,這樣會耗費CPU的資源。
2.2 CompletableFuture介紹
Netty、Guava分別擴展了Java 的 Future 接口,方便異步編程。
Java 8新增的CompletableFuture類正是吸收了所有Google Guava中ListenableFuture和SettableFuture的特征,還提供了其它強大的功能,讓Java擁有了完整的非阻塞編程模型:Future、Promise 和 Callback(在Java8之前,只有無Callback 的Future)。
CompletableFuture能夠將回調放到與任務不同的線程中執行,也能將回調作為繼續執行的同步函數,在與任務相同的線程中執行。它避免了傳統回調最大的問題,那就是能夠將控制流分離到不同的事件處理器中。
CompletableFuture彌補了Future模式的缺點。在異步的任務完成后,需要用其結果繼續操作時,無需等待。可以直接通過thenAccept、thenApply、thenCompose等方式將前面異步處理的結果交給另外一個異步事件處理線程來處理。
三. CompletableFuture特性
3.1 CompletableFuture的靜態工廠方法
方法名 | 描述 |
---|---|
runAsync(Runnable runnable) | 使用ForkJoinPool.commonPool()作為它的線程池執行異步代碼。 |
runAsync(Runnable runnable, Executor executor) | 使用指定的thread pool執行異步代碼。 |
supplyAsync(Supplier<U> supplier) | 使用ForkJoinPool.commonPool()作為它的線程池執行異步代碼,異步操作有返回值 |
supplyAsync(Supplier<U> supplier, Executor executor) | 使用指定的thread pool執行異步代碼,異步操作有返回值 |
runAsync 和 supplyAsync 方法的區別是runAsync返回的CompletableFuture是沒有返回值的。
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { System.out.println("Hello"); }); try { future.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("CompletableFuture");
而supplyAsync返回的CompletableFuture是由返回值的,下面的代碼打印了future的返回值。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello"); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("CompletableFuture");
3.2 Completable
方法名 | 描述 |
---|---|
complete(T t) | 完成異步執行,并返回future的結果 |
completeExceptionally(Throwable ex) | 異步執行不正常的結束 |
future.get()在等待執行結果時,程序會一直block,如果此時調用complete(T t)會立即執行。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello"); future.complete("World"); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }
執行結果:
World
可以看到future調用complete(T t)會立即執行。但是complete(T t)只能調用一次,后續的重復調用會失效。
如果future已經執行完畢能夠返回結果,此時再調用complete(T t)則會無效。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } future.complete("World"); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }
執行結果:
Hello
如果使用completeExceptionally(Throwable ex)則拋出一個異常,而不是一個成功的結果。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello"); future.completeExceptionally(new Exception()); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }
執行結果:
java.util.concurrent.ExecutionException: java.lang.Exception
...
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。