在這裏首先介紹下Callable和Future,咱們知道一般建立線程的2種方式,一種是直接繼承Thread,另一種就是實現Runnable接口,可是這兩種方式建立的線程不返回結果,而Callable是和Runnable相似的接口定義,可是經過實現Callable接口建立的線程能夠有返回值,返回值類型能夠任意定義。java
public interface Callable<V> { /** * 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; }
能夠看到,這是一個泛型接口,call()函數返回的類型就是傳遞進來的V類型。設計模式
那麼怎麼使用Callable呢?通常狀況下是配合ExecutorService來使用的,在ExecutorService接口中聲明瞭若干個submit方法的重載版本:異步
<T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task);
第一個submit方法裏面的參數類型就是Callable。Callable通常是和ExecutorService配合來使用的,經過ExecutorService的實例submit獲得Future對象。ide
Future接口以下:函數
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning);// 試圖取消對此任務的執行 boolean isCancelled(); // 若是在任務正常完成前將其取消,則返回true boolean isDone(); // 若是任務已完成(無論是正常仍是異常),則返回true V get() throws InterruptedException, ExecutionException; // 方法用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回; // 用來獲取執行結果,若是在指定時間內,還沒獲取到結果,就直接返回null; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future用於表示異步計算的結果。它的實現類是FutureTask。spa
若是不想分支線程阻塞主線程,又想取得分支線程的執行結果,就用FutureTask線程
FutureTask實現了RunnableFuture接口,這個接口的定義以下:設計
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
能夠看出RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實現了RunnableFuture接口。因此它既能夠做爲Runnable被線程執行,又能夠做爲Future獲得Callable的返回值。code
package demo.future; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; /** * 試驗 Java 的 Future 用法 */ public class FutureTest { public static class Task implements Callable<String> { @Override public String call() throws Exception { String tid = String.valueOf(Thread.currentThread().getId()); System.out.printf("Thread#%s : in call\n", tid); return tid; } } public static void main(String[] args) throws InterruptedException, ExecutionException { List<Future<String>> results = new ArrayList<Future<String>>(); ExecutorService es = Executors.newCachedThreadPool(); for(int i=0; i<100;i++) results.add(es.submit(new Task())); for(Future<String> res : results) System.out.println(res.get()); } }
持有Future對象,能夠調用cancel(),並所以可使用它來中斷某個特定任務,若是將ture傳遞給cancel(),那麼它就會擁有該線程上調用interrupt()以中止這個線程的權限。所以,cancel()是一種中斷由Executor啓動的單個線程的方式。對象
cancel()通常是搭配get()方法來使用的。比方說,有一種設計模式是設定特定的時間,而後去執行一個做業的線程,若是該做業可以在設定的時間內執行完畢,則直接返回結果,若是不能執行完畢,則中斷做業的執行,繼續執行下一個做業,在這種模式下,使用Callable和Future來實現是一個很是好的解決方案。