Java 1.5開始, 提供了 Callable
和 Future
, 經過它們能夠在任務執行完畢以後獲得任務執行結果.多線程
當須要調用幾個執行很慢的方法時, 可使用多線程一塊兒執行這幾個方法, 等全部方法執行完畢後獲得執行結果, 在進行別的處理.dom
Future 的主要方法ide
Future
接口主要包括 5 個方法:spa
get()
方法能夠當任務結束後返回一個結果, 若是調用時, 工做尚未結束, 則會阻塞線程, 直到任務執行完畢.線程
get(long timeout,TimeUnit unit)
作多等待 timeout
的時間就會返回結果.3d
cancel(boolean mayInterruptIfRunning)
方法能夠用來中止一個任務.code
isDone()
方法判斷當前方法是否完成.blog
isCancel()
方法判斷當前方法是否取消.接口
Future 示例 demo遊戲
需求場景: 等早餐過程當中, 包子須要 3 秒, 涼菜須要 1 秒, 普通的多線程須要四秒才能完成. 先等涼菜, 再等包子, 由於等涼菜時, 普通多線程啓動 start()
方法, 執行 run()
中具體方法時, 沒有返回結果, 因此若是要等有返回結果, 必須是要1秒結束後才知道結果.
public static void main(String[] args) throws InterruptedException, ExecutionException { long start = System.currentTimeMillis(); // 等涼菜 Callable ca1 = new Callable() { @Override public String call() throws Exception { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return "涼菜準備完畢"; } }; FutureTask<String> ft1 = new FutureTask<String>(ca1); new Thread(ft1).start(); // 等包子 -- 必需要等待返回的結果,因此要調用join方法 Callable ca2 = new Callable() { @Override public Object call() throws Exception { try { Thread.sleep(1000 * 3); } catch (InterruptedException e) { e.printStackTrace(); } return "包子準備完畢"; } }; FutureTask<String> ft2 = new FutureTask<String>(ca2); new Thread(ft2).start(); System.out.println(ft1.get()); System.out.println(ft2.get()); long end = System.currentTimeMillis(); System.out.println("準備完畢時間:" + (end - start)); }
還有一個比較典型的例子就是設置超時時間:
//固定大小的線程池,同時只能接受5個任務 static ExecutorService mExecutor = Executors.newFixedThreadPool(5); final static long timeout = 4 ; /** * 模擬在預約時間內獲取廣告信息 * @throws InterruptedException */ static void rederPageWithAd(final String pageTitle) throws InterruptedException{ Future<String> f = mExecutor.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println("開始加載廣告信息"); int randomTime = new Random().nextInt(5) + 1;//限制耗時不會出現0s,不會大於10s Thread.sleep(100 * 1000); System.out.println("正常加載廣告耗時:" + randomTime +"s"); return pageTitle; } }); String page; try { //在預計時間內等待 System.out.println("預期任務執行完時間:" + timeout + "s"); //page = f.get(); page = f.get(timeout, TimeUnit.SECONDS); } catch (ExecutionException e) { page = "出現執行異常,顯示默認的廣告頁面"; } catch (TimeoutException e) { page = "任務執行超時,顯示默認的廣告頁面"; f.cancel(true);//取消沒有執行完的任務,設置爲ture說明任務能被中斷,不然執行中的任務要完成 } System.out.println("成功加載廣告頁面:" + page); } public static void main(String[] args) { try { List<String> titleList = new ArrayList<String>(); titleList.add("體育賽事"); titleList.add("娛樂新聞"); titleList.add("實時聚焦"); titleList.add("國際諮詢"); titleList.add("影視天下"); titleList.add("遊戲風雲"); for (String string : titleList) { rederPageWithAd(string); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ /** * 只有執行了shutdown方法,執行isTerminated纔有效。不然isTerminated一直爲ture */ mExecutor.shutdown(); while(true){ if(mExecutor.isTerminated()){ System.out.println("全部任務都執行完了,關閉線程池"); break; } } } }
值得注意的是: 當主線程調用 Future
的 get
方法的時候會獲取到從線程中返回的結果數據. 若是在線程的執行過程當中發生了異常, get
會獲取到異常的信息.