程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 簡析Java中的util.concurrent.Future接口

簡析Java中的util.concurrent.Future接口

編輯:關於JAVA

簡析Java中的util.concurrent.Future接口。本站提示廣大學習愛好者:(簡析Java中的util.concurrent.Future接口)文章只能為提供參考,不一定能成為您想要的結果。以下是簡析Java中的util.concurrent.Future接口正文


在一個單線程運用中,當你挪用一個辦法只要盤算停止才會前往成果( IOUtils.toString()  comes from Apache Commons IO ):
 

public String downloadContents(URL url) throws IOException {
  try(InputStream input = url.openStream()) {
    return IOUtils.toString(input, StandardCharsets.UTF_8);
  }
}
 
//...
 
final Future<String> contents = downloadContents(new URL("http://www.example.com"));

downloadContents() 看上去是有害的, 然則它須要隨意率性長的時光來完成。同時,為了削減延遲,在期待成果的時代,你能夠須要同時自力的處置其它的任務。之前你能夠會啟動一個新的線程 或許期待成果(同享內存,鎖,蹩腳的 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> 對象。 這個對象是一個promise那末未來字符串類型就是可用的,固然我們不曉得甚麼時刻,然則會保存這個援用直到它返有成果前往,你便可以經由過程Future.get()來獲得它。 換句話說,Future是一個署理或許一個對象的包裝,不是真實的目的對象。一旦異步盤算完成,你便可以提取它。 那末Future供給了甚麼樣的接口呢?

Future.get()是最主要的辦法。它壅塞和期待直到許諾的成果是可用狀況, 是以假如我們確切須要這個字符串,就挪用get() 辦法然後期待。 還有一個接收超時參數的重載版本,假如哪裡湧現成績你就不消一向期待下去,跨越設准時間就會拋出 TimeoutException。


在某些情形下,你能夠想一直地偷偷看看Future能否可用了。這可以經由過程isDone()來完成。想象一個情形,你的用戶期待某些異步的盤算,你想讓他曉得這類情形, 同時去做一些其它的盤算:
 

final Future<String> contentsFuture = startDownloading(new URL("http://www.example.com"));
while (!contentsFuture.isDone()) {
  askUserToWait();
  doSomeComputationInTheMeantime();
}
contentsFuture.get();

最初Future.get()挪用的內容會包管立時前往,不會被壅塞,由於Future.isDone() 前往了true。假如你遵守這個形式,就不會忙於每秒百萬次的瓜代期待和挪用isDone()。


撤消futrues是最初一個我們還沒有籠罩到的。想象你啟動了異步的任務而且你只能期待一些時光, 假如2秒鐘後,我們廢棄,或許把毛病傳遞出去,或許采取暫時計劃處理它。但是,你是一個好市平易近,你應當告知這個future對象:我不須要你了,你別管了。 那末你可以經由過程停滯過時的義務,來勤儉資本。語法很簡略:
 

contentsFuture.cancel(true);  //meh...


我們都愛好隱蔽的,布爾類型的參數,對嗎?撤消可以經由過程兩種方法來完成:在義務啟動前經由過程傳遞false參數來撤消,條件是當Future表達的成果盤算開端之前。一旦Callable.call()曾經運轉到一半,那末我們想讓它停止,假如我們傳遞true,那末Future.call()就會具有侵入性,試圖打斷正在運轉的任務。你認為如許好嗎?景象那些拋出InterruptedException這個申明狼籍的異常的辦法,如Thread.sleep(), Object.wait(),Condition.await(),等,乃至包含Future.get(). 假如你被壅塞在這類辦法而且有人決議撤消你的挪用,他們會毫無疑問的拋出InterruptionException,並收回有人要打斷以後運轉的義務。


是以我們如今明確了Future是甚麼--- 一個占位符,你可以在將來獲得目的對象。就像關於一輛車,還沒有制作出來的鑰匙。然則你如何能力在運用法式中取得Future的實例? 兩種最通俗的資本是線程池和異步辦法(線程池支撐)。是以, startDownloading()辦法可以被重寫為:
 

private final ExecutorService pool = Executors.newFixedThreadPool(10);
 
public Future<String> startDownloading(final URL url) throws IOException {
  return pool.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
      try (InputStream input = url.openStream()) {
        return IOUtils.toString(input, StandardCharsets.UTF_8);
      }
    }
  });
}


固然有年夜量的繁瑣的語法成績,然則根本思惟是簡略的: 把須要長時光運轉的盤算包裝到可挪用的<String>,並submit()到線程池,這個線程池包括10個線程。 提交後前往Future<String>的完成,就像以某種方法鏈接到你的義務和線程池。顯著的你的義務不會被立刻履行,相反它被放到一個隊列中,稍後會被線程拉出來, 如今須要弄清晰cancel()的兩個特殊的意義是甚麼——你可以撤消在隊列中逗留的義務,也能夠撤消早已運轉的義務,但這是一件比擬龐雜的工作。


你還可以在Spring 和 EJB 碰上Future。好比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)
    );
  }
}


留意,我們簡略地經由過程包裝成果到AsyncResult來完成Future,然則這個辦法自己不會與線程池交互或許異步處置。稍後 Spring會署理一切的挪用來startDownloading()並在線程池中履行。 在EJB中,雷同的特征經由過程加@Asynchronousannotation 來完成。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved