国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Akka系列(五):Java和Scala中的Future

YJNldm / 1588人閱讀

摘要:隨著的核數的增加,異步編程模型在并發領域中的得到了越來越多的應用,由于是一門函數式語言,天然的支持異步編程模型,今天主要來看一下和中的,帶你走入異步編程的大門。

隨著CPU的核數的增加,異步編程模型在并發領域中的得到了越來越多的應用,由于Scala是一門函數式語言,天然的支持異步編程模型,今天主要來看一下Java和Scala中的Futrue,帶你走入異步編程的大門。

Future

很多同學可能會有疑問,Futrue跟異步編程有什么關系?從Future的表面意思是未來,一個Future對象可以看出一個將來得到的結果,這就和異步執行的概念很像,你只管自己去執行,只要將最終的結果傳達給我就行,線程不必一直暫停等待結果,可以在具體異步任務執行的時候去執行其他操作,舉個例子:

我們現在在執行做飯這么一個任務,它需要煮飯,燒菜,擺置餐具等操作,如果我們通過異步這種概念去執行這個任務,比如煮飯可能需要比較久的時間,但煮飯這個過程又不需要我們管理,我們可以利用這段時間去燒菜,燒菜過程中也可能有空閑時間,我們可以去擺置餐具,當電飯鍋通知我們飯燒好了,菜也燒好了,最后我們就可以開始吃飯了,所以說,上面的“煮飯 -> 飯”,“燒菜 -> 菜”都可以看成一個Future的過程。

Java中的Future

在Java的早期版本中,我們不能得到線程的執行結果,不管是繼承Thread類還是實現Runnable接口,都無法獲取線程的執行結果,所以我們只能在線程執行的run方法里去做相應的一些業務邏輯操作,但隨著Java5的發布,它為了我們帶來了Callable和Future接口,我們可以利用這兩個接口的特性來獲取線程的執行結果。

Callable接口

通俗的講,Callable接口也是一個線程執行類接口,那么它跟Runnable接口有什么區別呢?我們先來看看它們兩個的定義:

1.Callable接口:

@FunctionalInterface
public interface Callable {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

2.Runnable接口:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

從上面的定義,我們可以看出,兩者最大的區別就是對應的執行方法是否有返回值。Callable接口中call方法具有返回值,這便是為什么我們可以通過Callable接口來得到一個線程執行的返回值或者是異常信息。

Future接口

上面說到既然Callable接口能返回線程執行的結果,那么為什么還需要Future接口呢?因為Callable接口執行的結果只是一個將來的結果值,我們若是需要得到具體的結果就必須利用Future接口,另外Callable接口需要委托ExecutorService的submit提交任務去執行,我們來看看它是如何定義的:

  Future submit(Callable task);
 
 public  Future submit(Callable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
 

從submit的方法定義也可以看出它的返回值是一個Future接口類型的值,這里其實是RunnableFuture接口,這是一個很重要的接口,我們來看一下它的定義:

public interface RunnableFuture extends Runnable, Future {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

這個接口分別繼承了Runnable和Future接口,而FutureTask又實現了RunnableFuture接口,它們之間的關系:

RunnableFuture有以下兩個特點:

繼承Runnable接口,還是以run方法作為線程執行入口,其實上面submit方法的具體實現也可以看出,一個Callable的Task再執行的時候會被包裝成RunnableFuture,然后以FutureTask作為實現類,執行FutureTask時,還是執行其的run方法,只不過run方法里面的業務邏輯是由我們定義的call方法的內容,當然再執行run方法時,程序會自動將call方法的執行結果幫我們包裝起來,對外部表現成一個Future對象。

繼承Future接口,通過實現Future接口中的方法更新或者獲取線程的的執行狀態,比如其中的cancel(),isDone(),get()等方法。

Future程序示例與結果獲取

下面是一個簡單的Future示例,我們先來看一下代碼:

ExecutorService es = Executors.newSingleThreadExecutor();
Future f = es.submit(() -> {
        System.out.println("execute call");
        Thread.sleep(1000);
        return 5;
    });
try {
    System.out.println(f.isDone()); //檢測任務是否完成
    System.out.println(f.get(2000, TimeUnit.MILLISECONDS));
    System.out.println(f.isDone()); //檢測任務是否完成
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
} catch (TimeoutException e) {
    e.printStackTrace();
}

上面的代碼使用了lambda表達式,有興趣的同學可以自己去了解下,這里我們首先構建了一個ExecutorService,然后利用submit提交執行Callable接口的任務。

為什么是Callable接口呢? 其實這里我們并沒有顯示聲明Callable接口,這里lambda會幫我們自動進行類型推導,首先submit接受Callable接口或Runnble接口類型作為參數,而這里我們又給定了返回值,所以lambda能自動幫我們推導出內部是一個Callable接口參數。

到這里我們應該大致清楚了在Java中的得到Future,那么我們又是如何從Future中得到我們想要的值呢?這個結論其實很容易得出,你只需要去跑一下上面的程序即可,在利用get去獲取Future中的值時,線程會一直阻塞,直到返回值或者超時,所以Future中的get方法是阻塞,所以雖然利用Future似乎是異步執行任務,但是在某些需求上還是會阻塞的,并不是真正的異步,stackoverflow上有兩個討論說明了這個問題Future.get,without blocking when task complete,有興趣的同學可以去看看。

Scala中的Future

Scala中的Future相對于Java的Future有什么不同呢?我總結了一下幾點:

1.創建Future變得很容易

異步編程作為函數式語言的一大優勢,Scala對于Future的支持也是非常棒的,首先它也提供了Futrue接口,但不同的是我們在構建Future對象是不用像Java一樣那么繁瑣,并且非常簡單,舉個例子:

import scala.concurrent._ 
import ExecutionContext.Implicits.global 

val f: Future[String] = Future { "Hello World!" }

是不是非常簡單,也大大降低了我們使用Future的難度。

2.提供真正異步的Future

前面我們也說到,Java中的Future并不是全異步的,當你需要Future里的值的時候,你只能用get去獲取它,亦或者不斷訪問Future的狀態,若完成再去取值,但其意義上便不是真正的異步了,它在獲取值的時候是一個阻塞的操作,當然也就無法執行其他的操作,直到結果返回。

但在Scala中,我們無需擔心,雖然它也提供了類似Java中獲取值的方式,比如:

Future Java Scala
判斷任務是否完成 isDone isCompleted
獲取值 get value

但是我們并不推薦這么做,因為這么做又回到了Java的老路上了,在Scala中我們可以利用Callback來獲取它的結果:

val fut = Future {
    Thread.sleep(1000)
    1 + 1
}

fut onComplete {
    case Success(r) => println(s"the result is ${r}")
    case _ => println("some Exception")
}

println("I am working")
Thread.sleep(2000)

這是一個簡單的例子,Future在執行完任務后會進行回調,這里使用了onComplete,也可以注冊多個回調函數,但不推薦那么做,因為你不能保證這些回調函數的執行順序,其他的一些回調函數基本都是基于onComplete的,有興趣的同學可以去閱讀一下Future的源碼。

我們先來看一下它的運行結果:

I am working
the result is 2

從結果中我們可以分析得出,我們在利用Callback方式來獲取Future結果的時候并不會阻塞,而只是當Future完成后會自動調用onComplete,我們只需要根據它的結果再做處理即可,而其他互不依賴的操作可以繼續執行不會阻塞。

3.強大的Future組合

前面我們講的較多的都是單個Future的情況,但是在真正實際應用時往往會遇到多個Future的情況,那么在Scala中是如何處理這種情況的呢?

Scala中的有多種方式來組合Future,那我們就來看看這些方式吧。

1.flatMap

我們可以利用flatMap來組合多個Future,不多說,先上代碼:

val fut1 = Future {
    println("enter task1")
    Thread.sleep(2000)
    1 + 1
}

val fut2 = Future {
    println("enter task2")
    Thread.sleep(1000)
    2 + 2
}

fut1.flatMap { v1 =>
    fut2.map { v2 =>
      println(s"the result is ${v1 + v2}")
    }
}
Thread.sleep(2500)

利用flatMap確實能組合Future,但代碼的閱讀性實在是有點差,你能想象5個甚至10個map層層套著么,所以我們并不推薦這么做,但是我們需要了解這種方式,其他簡潔的方式可能最終轉化成的版本也許就是這樣的。

2.for yield表達式

我們只是把上面關于flatMap的代碼替換一下,看下面:

for {
    v1 <- fut1
    v2 <- fut2
} yield println(s"the result is ${v1 + v2}")

看上去是不是比之前的方式簡潔多了,這也是我們在面對Future組合時推薦的方式,當然不得不說for yield表達式是一種語法糖,它最終還是會被翻譯成我們常見的方法,比如flatMap,map,filter等,感興趣的可以參考它的官方文檔。for yield表達式

總的來說Scala中的Future確實強大,在實現真正異步的情況下,為我們提供許多方便而又簡潔的操作模式,其實比如還有Future.reduce(),Future.traverse(),Future.sequence()等方法,這些方法的具體功能和具體使用這里就不講了,但相關的示例代碼都會在我的示例工程里,有興趣的同學可以去跑跑加深理解。源碼鏈接

總結

這篇文章主要講解了JVM生態上兩大語言Java和Scala在異步編程上的一些表現,這里主要是Future機制,在清楚明白它的概念后,我們才能寫出更好的程序,雖然本篇文章沒有涉及到Akka相關的內容,但是Akka本身是用Scala寫的,而且大量使用了Scala中的Future,相信通過對Future的學習,對Akka的理解會有一定的幫助。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70069.html

相關文章

  • JVM并發編程模型覽

    摘要:本文介紹和點評上的等并發編程模型。異步更適合并發編程。同步使線程阻塞,導致等待。基本模型這是最簡單的模型,創建線程來執行一個任務,完畢后銷毀線程。響應式編程是一種面向數據流和變化傳播的編程模式。起源于電信領域的的編程模型。 本文介紹和點評JVM上的Thread, Thread Pool, Future, Rx, async-await, Fiber, Actor等并發編程模型。本人經驗...

    cppowboy 評論0 收藏0
  • JVM并發編程模型覽

    摘要:本文介紹和點評上的等并發編程模型。異步更適合并發編程。同步使線程阻塞,導致等待。基本模型這是最簡單的模型,創建線程來執行一個任務,完畢后銷毀線程。響應式編程是一種面向數據流和變化傳播的編程模式。起源于電信領域的的編程模型。 本文介紹和點評JVM上的Thread, Thread Pool, Future, Rx, async-await, Fiber, Actor等并發編程模型。本人經驗...

    wudengzan 評論0 收藏0
  • #yyds干貨盤點# 常用軟件框架,總有一個用的上

    摘要:一界面框架是微軟在其最新桌面操作系統中使用的圖形用戶界面。干貨盤點二服務在寫后臺代碼的過程中,經常會遇到要寫一些多帶帶的服務。這個傳統的控件開發起來很不方面,使用也不友好。發現有用的,這個第三方的框架,集成的很好,用起來也方便。一、Fluent Ribbon界面框架Fluent/Ribbon是微軟在其最新桌面操作系統Windows 7中使用的圖形用戶界面。 Windows平臺的進化,伴隨著系...

    番茄西紅柿 評論0 收藏2637
  • Akka系列(七):Actor持久化之Akka persistence

    摘要:源碼鏈接進階持久化插件有同學可能會問,我對不是很熟悉亦或者覺得單機存儲并不是安全,有沒有支持分布式數據存儲的插件呢,比如某爸的云數據庫答案當然是有咯,良心的我當然是幫你們都找好咯。 這次把這部分內容提到現在寫,是因為這段時間開發的項目剛好在這一塊遇到了一些難點,所以準備把經驗分享給大家,我們在使用Akka時,會經常遇到一些存儲Actor內部狀態的場景,在系統正常運行的情況下,我們不需要...

    miguel.jiang 評論0 收藏0
  • Akka系列(四):Akka中的共享內存模型

    摘要:共享內存相信對并發有所了解的同學都應該知道在推出后,對內存管理有了更高標準的規范了,這使我們開發并發程序也有更好的標準了,不會有一些模糊的定義導致的無法確定的錯誤。 通過前幾篇的學習,相信大家對Akka應該有所了解了,都說解決并發哪家強,JVM上面找Akka,那么Akka到底在解決并發問題上幫我們做了什么呢? 共享內存 眾所周知,在處理并發問題上面,最核心的一部分就是如何處理共享內存,...

    baukh789 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<