在Java中進行並行編程最經常使用的方式是繼承Thread類或者實現Runnable接口。這兩種方式的缺點是在任務完成後沒法直接獲取執行結果,必須經過共享變量或線程間通訊,使用起來很不方便。
從Java 1.5開始提供了Callable和Future兩個接口,經過使用它們能夠在任務執行完畢後獲得執行結果。
下面咱們來學習下如何使用Callable、Future和FutureTask。java
Callable接口位於java.util.concurrent包,這是一個泛型接口,裏面只聲明瞭一個call()方法:編程
public interface Callable<T> { T call() throws Exception; }
通常配合ExecutorService接口來使用它,在ExecutorService接口中聲明瞭幾個重載的submit方法:ide
<T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task);
第一個submit方法裏面的參數類型就是Callable,另外兩個本文暫時不涉及。函數
Future接口的實現類能夠對Runnable或者Callable的任務執行取消、查詢、獲取結果的操做。
Future接口也位於java.util.concurrent包下:學習
public interface Future<T> { /** *取消任務 *@param mayInterruptIfRunning *是否容許取消正在執行卻沒有執行完畢的任務,若是設置true,則表示能夠取消正在執行過程當中的任務 *若是任務正在執行,則返回true *若是任務尚未執行,則不管mayInterruptIfRunning爲true仍是false,返回true *若是任務已經完成,則不管mayInterruptIfRunning爲true仍是false,返回false */ boolean cancel(boolean mayInterruptIfRunning); /** *任務是否被取消成功,若是在任務正常完成前被取消成功,則返回 true */ boolean isCancelled(); /** *任務是否完成 */ boolean isDone(); /** *經過阻塞獲取執行結果 */ T get() throws InterruptedException, ExecutionException; /** *經過阻塞獲取執行結果。若是在指定的時間內沒有返回,則返回null */ T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
總結下來Future提供了三種功能:線程
- 判斷任務是否完成
- 可以中斷任務
- 可以獲取任務執行的結果
JDK中爲咱們提供了一個Future接口的實現類FutureTask,它有以下兩個構造函數。code
public FutureTask(Callable<T> callable) { } public FutureTask(Runnable runnable, T result) { }
import java.util.concurrent.*; public class Test { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); Task task = new Task(); Future<Integer> future = executorService.submit(task); executorService.shutdown(); System.out.println("主線程在執行任務..."); try { Thread.sleep(2000); } catch(InterruptedException ex) { ex.printStackTrace(); } try { System.out.println("task運行結果:"+future.get()); } catch (InterruptedException ex) { ex.printStackTrace(); } catch (ExecutionException ex) { ex.printStackTrace(); } System.out.println("全部任務執行完畢"); } } class Task implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("子線程在執行任務..."); //模擬任務耗時 Thread.sleep(5000); return 1000; } }
執行結果:繼承
子線程在執行任務...
主線程在執行任務...
task運行結果:1000
全部任務執行完畢接口
import java.util.concurrent.*; public class Test { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); Task task = new Task(); FutureTask<Integer> futureTask = new FutureTask<Integer>(task); executorService.submit(futureTask); executorService.shutdown(); System.out.println("主線程在執行任務..."); try { Thread.sleep(2000); } catch (InterruptedException ex) { ex.printStackTrace(); } try { System.out.println("task運行結果:"+futureTask.get()); } catch (InterruptedException ex) { ex.printStackTrace(); } catch (ExecutionException ex) { ex.printStackTrace(); } System.out.println("全部任務執行完畢"); } } class Task implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("子線程在執行任務..."); //模擬任務耗時 Thread.sleep(5000); return 1000; } }
執行結果:get
子線程在執行任務...主線程在執行任務...task運行結果:1000全部任務執行完畢