java.util.concurrent.Future基础
在此,我開始撰寫一系列有關編程語言中的未來概念(也稱為promise或delays )的文章,標題為: Back to the Future 。 由于對異步,事件驅動,并行和可伸縮系統的需求不斷增長,所以期貨是非常重要的抽象,如今比以往任何時候都更加重要。 在第一篇文章中,我們將發現最基本的java.util.concurrent.Future<T>接口。 稍后,我們將跳入其他框架,庫甚至語言。 Future<T>是相當有限的,但必須了解,ekhm,將來部分。
在單線程應用程序中,當您調用方法時,它僅在計算完成IOUtils.toString()返回( IOUtils.toString()來自Apache Commons IO ):
downloadContents()看起來是無害的1 ,但它甚至可能需要花費很長時間才能完成。 此外,為了減少延遲,您可能希望在等待結果的同時進行其他獨立的處理。 在過去,您將啟動一個新Thread并以某種方式等待結果(共享內存,鎖,可怕的wait() / notify()對等),使用Future<T>會更加愉快:
public static Future<String> startDownloading(URL url) {//... }final Future<String> contentsFuture = startDownloading(new URL("http://www.example.com")); //other computation final String contents = contentsFuture.get();我們將很快實現startDownloading() 。 目前,重要的是要了解這些原理。 startDownloading() 不阻塞,等待外部網站。 相反,它會立即返回,并返回輕量級的Future<String>對象。 此對象保證 String將來會可用。 不知道什么時候,但是保留此引用,一旦存在,您就可以使用Future.get()檢索它。 換句話說, Future是一個尚未存在的對象的代理或包裝。 異步計算完成后,您可以提取它。 那么Future提供了什么API?
Future.get()是最重要的方法。 它阻塞并等待,直到承諾的結果可用(已解決 )。 因此,如果我們確實需要該String ,則只需調用get()并等待。 有一個過載的版本可以接受超時,所以一旦出現問題,您將不會永遠等待。 如果等待時間太長,則會拋出TimeoutException 。
在某些用例中,您可能希望窺視“ Future ,如果結果尚不可用,請繼續。 使用isDone()可以做到這一點。 想象一下這樣一種情況,您的用戶正在等待一些異步計算,而您想讓他知道我們仍在等待并同時進行一些計算:
final Future<String> contentsFuture = startDownloading(new URL("http://www.example.com")); while (!contentsFuture.isDone()) {askUserToWait();doSomeComputationInTheMeantime(); }到最后調用contentsFuture.get()是保證立即返回,而不是因為塊Future.isDone()返回true 。 如果遵循上述模式,請確保您不忙于等待,每秒每秒調用isDone()數百萬次。
取消期貨是我們尚未討論的最后一個方面。 想象一下,您開始了一些異步作業,并且您只能在給定的時間內等待它。 如果2秒鐘后仍沒有出現,我們會放棄并傳播錯誤或解決它。 但是,如果您是一個好公民,您應該以某種方式告訴這個未來的目標:我不再需要您,那就算了。 通過不運行過時的任務來節省處理資源。 語法很簡單:
contentsFuture.cancel(true); //meh...我們都喜歡神秘的布爾參數,不是嗎? 取消有兩種口味。 通過將false傳遞給mayInterruptIfRunning參數,當Future表示尚未開始的計算結果時,我們僅取消尚未開始的任務。 但是,如果我們的Callable.call()已經在中間,則讓它結束。 但是,如果我們傳遞true ,則Future.cancel()將更具攻擊性,并嘗試中斷已經在運行的作業。 怎么樣? 考慮所有引發臭名昭著的InterruptedException方法,即Thread.sleep() , Object.wait() , Condition.await()以及許多其他方法(包括Future.get() )。 如果您禁止使用任何此類方法,而某人決定取消您的Callable ,則它們實際上將拋出InterruptedException ,表示有人試圖中斷當前正在運行的任務。
因此,我們現在了解什么是Future<T> –將來會得到的東西的占位符。 這就像尚未生產的汽車的鑰匙。 但是,實際上如何在應用程序中獲取Future<T>的實例? 兩種最常見的來源是線程池和異步方法(由您的線程池支持)。 因此,我們的startDownloading()方法可以重寫為:
private final ExecutorService pool = Executors.newFixedThreadPool(10);public Future<String> startDownloading(final URL url) throws IOException {return pool.submit(new Callable<String>() {@Overridepublic String call() throws Exception {try (InputStream input = url.openStream()) {return IOUtils.toString(input, StandardCharsets.UTF_8);}}}); }語法很多,但基本思想很簡單:將長時間運行的計算包裝在Callable<String>然后submit()它們submit()到10個線程的線程池中。 提交返回Future<String>某些實現,最有可能以某種方式鏈接到您的任務和線程池。 顯然,您的任務不會立即執行。 而是將其放置在隊列中,該隊列稍后(甚至可能更晚)由池中的線程輪詢。 現在應該清楚這兩種cancel()含義–您始終可以取消仍然駐留在該隊列中的任務。 但是取消已經運行的任務要復雜一些。
可以遇到Future另一個地方是Spring和EJB。 例如,在Spring框架中,您可以使用@Async注釋您的方法 :
@Async public Future<String> startDownloading(final URL url) throws IOException {try (InputStream input = url.openStream()) {return new AsyncResult<>(IOUtils.toString(input, StandardCharsets.UTF_8));} }注意,我們只是將結果包裝在實現Future AsyncResult 。 但是該方法本身不處理線程池或異步處理。 Spring稍后將代理所有對startDownloading()調用,并在線程池中運行它們。 EJB中的@Asynchronous批注提供了完全相同的功能。
因此,我們了解了很多有關java.util.concurrent.Future 。 現在該承認了–該界面非常有限,尤其是與其他語言相比時。 以后再說。
1 –您不熟悉Java 7的try-with-resources功能嗎? 您現在最好切換到Java 7。 Java 6將在兩周內不再維護。
參考: NoBlogDefFound博客上來自我們的JCG合作伙伴 Tomasz Nurkiewicz的java.util.concurrent.Future基礎 。
翻譯自: https://www.javacodegeeks.com/2013/02/java-util-concurrent-future-basics.html
總結
以上是生活随笔為你收集整理的java.util.concurrent.Future基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人人安卓版下载(人人安卓版)
- 下一篇: linux 内核驱动(linux驱动内核