Java8新的異步編程方式 CompletableFuture(一)

一. Future

JDK 5引入了Future模式谚殊。Future接口是Java多線程Future模式的實現(xiàn),在java.util.concurrent包中碑隆,可以來進行異步計算赠法。

Future模式是多線程設(shè)計常用的一種設(shè)計模式对雪。Future模式可以理解成:我有一個任務(wù)怜庸,提交給了Future当犯,F(xiàn)uture替我完成這個任務(wù)。期間我自己可以去做任何想做的事情割疾。一段時間之后嚎卫,我就便可以從Future那兒取出結(jié)果。

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接口的方法介紹如下:

  • boolean cancel (boolean mayInterruptIfRunning) 取消任務(wù)的執(zhí)行。參數(shù)指定是否立即中斷任務(wù)執(zhí)行麻昼,或者等等任務(wù)結(jié)束
  • boolean isCancelled () 任務(wù)是否已經(jīng)取消奠支,任務(wù)正常完成前將其取消,則返回 true
  • boolean isDone () 任務(wù)是否已經(jīng)完成抚芦。需要注意的是如果任務(wù)正常終止胚宦、異常或取消燕垃,都將返回true
  • V get () throws InterruptedException, ExecutionException 等待任務(wù)執(zhí)行結(jié)束枢劝,然后獲得V類型的結(jié)果。InterruptedException 線程被中斷異常卜壕, ExecutionException任務(wù)執(zhí)行異常您旁,如果任務(wù)被取消,還會拋出CancellationException
  • V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一樣轴捎,多了設(shè)置超時時間鹤盒。參數(shù)timeout指定超時時間,uint指定時間的單位侦副,在枚舉類TimeUnit中有相關(guān)的定義侦锯。如果計 算超時,將拋出TimeoutException

一般情況下秦驯,我們會結(jié)合Callable和Future一起使用尺碰,通過ExecutorService的submit方法執(zhí)行Callable,并返回Future译隘。

        ExecutorService executor = Executors.newCachedThreadPool();

        Future<String> future = executor.submit(() -> { //Lambda 是一個 callable亲桥, 提交后便立即執(zhí)行,這里返回的是 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 的執(zhí)行結(jié)果题篷,執(zhí)行完畢之后打印出來
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {

        } finally {
            executor.shutdown();
        }

比起future.get(),其實更推薦使用get (long timeout, TimeUnit unit) 方法厅目,設(shè)置了超時時間可以防止程序無限制的等待future的結(jié)果番枚。

二. CompletableFuture介紹

2.1 Future模式的缺點

  • Future雖然可以實現(xiàn)獲取異步執(zhí)行結(jié)果的需求法严,但是它沒有提供通知的機制,我們無法得知Future什么時候完成葫笼。

  • 要么使用阻塞深啤,在future.get()的地方等待future返回的結(jié)果,這時又變成同步操作渔欢。要么使用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能夠?qū)⒒卣{(diào)放到與任務(wù)不同的線程中執(zhí)行涡相,也能將回調(diào)作為繼續(xù)執(zhí)行的同步函數(shù)哲泊,在與任務(wù)相同的線程中執(zhí)行。它避免了傳統(tǒng)回調(diào)最大的問題催蝗,那就是能夠?qū)⒖刂屏鞣蛛x到不同的事件處理器中切威。

CompletableFuture彌補了Future模式的缺點。在異步的任務(wù)完成后丙号,需要用其結(jié)果繼續(xù)操作時先朦,無需等待∪В可以直接通過thenAccept喳魏、thenApply、thenCompose等方式將前面異步處理的結(jié)果交給另外一個異步事件處理線程來處理怀薛。

三. CompletableFuture特性

3.1 CompletableFuture的靜態(tài)工廠方法

方法名 描述
runAsync(Runnable runnable) 使用ForkJoinPool.commonPool()作為它的線程池執(zhí)行異步代碼刺彩。
runAsync(Runnable runnable, Executor executor) 使用指定的thread pool執(zhí)行異步代碼。
supplyAsync(Supplier<U> supplier) 使用ForkJoinPool.commonPool()作為它的線程池執(zhí)行異步代碼枝恋,異步操作有返回值
supplyAsync(Supplier<U> supplier, Executor executor) 使用指定的thread pool執(zhí)行異步代碼迂苛,異步操作有返回值

runAsync 和 supplyAsync 方法的區(qū)別是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) 完成異步執(zhí)行,并返回future的結(jié)果
completeExceptionally(Throwable ex) 異步執(zhí)行不正常的結(jié)束

future.get()在等待執(zhí)行結(jié)果時呐能,程序會一直block念搬,如果此時調(diào)用complete(T t)會立即執(zhí)行抑堡。

        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();
        }

執(zhí)行結(jié)果:

World

可以看到future調(diào)用complete(T t)會立即執(zhí)行。但是complete(T t)只能調(diào)用一次朗徊,后續(xù)的重復(fù)調(diào)用會失效首妖。

如果future已經(jīng)執(zhí)行完畢能夠返回結(jié)果,此時再調(diào)用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();
        }

執(zhí)行結(jié)果:

Hello

如果使用completeExceptionally(Throwable ex)則拋出一個異常有缆,而不是一個成功的結(jié)果。

        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();
        }

執(zhí)行結(jié)果:

java.util.concurrent.ExecutionException: java.lang.Exception
...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末温亲,一起剝皮案震驚了整個濱河市棚壁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌栈虚,老刑警劉巖袖外,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異魂务,居然都是意外死亡曼验,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門粘姜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鬓照,“玉大人,你說我怎么就攤上這事孤紧∥胖” “怎么了女气?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵艇劫,是天一觀的道長态秧。 經(jīng)常有香客問我,道長咙轩,這世上最難降的妖魔是什么获讳? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮活喊,結(jié)果婚禮上丐膝,老公的妹妹穿的比我還像新娘。我一直安慰自己钾菊,他們只是感情好帅矗,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著煞烫,像睡著了一般浑此。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滞详,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天凛俱,我揣著相機與錄音紊馏,去河邊找鬼。 笑死蒲犬,一個胖子當(dāng)著我的面吹牛朱监,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播原叮,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼赫编,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奋隶?” 一聲冷哼從身側(cè)響起擂送,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎达布,沒想到半個月后团甲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逾冬,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡黍聂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了身腻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片产还。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嘀趟,靈堂內(nèi)的尸體忽然破棺而出脐区,到底是詐尸還是另有隱情,我是刑警寧澤她按,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布牛隅,位于F島的核電站,受9級特大地震影響酌泰,放射性物質(zhì)發(fā)生泄漏媒佣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一陵刹、第九天 我趴在偏房一處隱蔽的房頂上張望默伍。 院中可真熱鬧,春花似錦衰琐、人聲如沸也糊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狸剃。三九已至,卻和暖如春狗热,著一層夾襖步出監(jiān)牢的瞬間捕捂,已是汗流浹背瑟枫。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留指攒,地道東北人慷妙。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像允悦,于是被迫代替她去往敵國和親膝擂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容