本章介紹線程池中的Callable和Future。
Callable 和 Future 簡介
示例和源碼分析(基於JDK1.7.0_40)html
轉載請註明出處:http://www.cnblogs.com/skywang12345/p/3544116.htmljava
Callable 和 Future 是比較有趣的一對組合。當咱們須要獲取線程的執行結果時,就須要用到它們。Callable用於產生結果,Future用於獲取結果。多線程
1. Callable架構
Callable 是一個接口,它只包含一個call()方法。Callable是一個返回結果而且可能拋出異常的任務。異步
爲了便於理解,咱們能夠將Callable比做一個Runnable接口,而Callable的call()方法則相似於Runnable的run()方法。ide
Callable的源碼以下:函數
public interface Callable<V> { V call() throws Exception; }
說明:從中咱們能夠看出Callable支持泛型。源碼分析
2. Futurethis
Future 是一個接口。它用於表示異步計算的結果。提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。spa
Future的源碼以下:
public interface Future<V> { // 試圖取消對此任務的執行。 boolean cancel(boolean mayInterruptIfRunning) // 若是在任務正常完成前將其取消,則返回 true。 boolean isCancelled() // 若是任務已完成,則返回 true。 boolean isDone() // 若有必要,等待計算完成,而後獲取其結果。 V get() throws InterruptedException, ExecutionException; // 若有必要,最多等待爲使計算完成所給定的時間以後,獲取其結果(若是結果可用)。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
說明: Future用於表示異步計算的結果。它的實現類是FutureTask,在講解FutureTask以前,咱們先看看Callable, Future, FutureTask它們之間的關係圖,以下:
說明:
(01) RunnableFuture是一個接口,它繼承了Runnable和Future這兩個接口。RunnableFuture的源碼以下:
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
(02) FutureTask實現了RunnableFuture接口。因此,咱們也說它實現了Future接口。
咱們先經過一個示例看看Callable和Future的基本用法,而後再分析示例的實現原理。
1 import java.util.concurrent.Callable; 2 import java.util.concurrent.Future; 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.ExecutionException; 6 7 class MyCallable implements Callable { 8 9 @Override 10 public Integer call() throws Exception { 11 int sum = 0; 12 // 執行任務 13 for (int i=0; i<100; i++) 14 sum += i; 15 //return sum; 16 return Integer.valueOf(sum); 17 } 18 } 19 20 public class CallableTest1 { 21 22 public static void main(String[] args) 23 throws ExecutionException, InterruptedException{ 24 //建立一個線程池 25 ExecutorService pool = Executors.newSingleThreadExecutor(); 26 //建立有返回值的任務 27 Callable c1 = new MyCallable(); 28 //執行任務並獲取Future對象 29 Future f1 = pool.submit(c1); 30 // 輸出結果 31 System.out.println(f1.get()); 32 //關閉線程池 33 pool.shutdown(); 34 } 35 }
運行結果:
4950
結果說明:
在主線程main中,經過newSingleThreadExecutor()新建一個線程池。接着建立Callable對象c1,而後再經過pool.submit(c1)將c1提交到線程池中進行處理,而且將返回的結果保存到Future對象f1中。而後,咱們經過f1.get()獲取Callable中保存的結果;最後經過pool.shutdown()關閉線程池。
1. submit()
submit()在java/util/concurrent/AbstractExecutorService.java中實現,它的源碼以下:
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); // 建立一個RunnableFuture對象 RunnableFuture<T> ftask = newTaskFor(task); // 執行「任務ftask」 execute(ftask); // 返回「ftask」 return ftask; }
說明:submit()經過newTaskFor(task)建立了RunnableFuture對象ftask。它的源碼以下:
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); }
2. FutureTask的構造函數
FutureTask的構造函數以下:
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); // callable是一個Callable對象 this.callable = callable; // state記錄FutureTask的狀態 this.state = NEW; // ensure visibility of callable }
3. FutureTask的run()方法
咱們繼續回到submit()的源碼中。
在newTaskFor()新建一個ftask對象以後,會經過execute(ftask)執行該任務。此時ftask被看成一個Runnable對象進行執行,最終會調用到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中實現,源碼以下:
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { // 將callable對象賦值給c。 Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { // 執行Callable的call()方法,並保存結果到result中。 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } // 若是運行成功,則將result保存 if (ran) set(result); } } finally { runner = null; // 設置「state狀態標記」 int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
說明:run()中會執行Callable對象的call()方法,而且最終將結果保存到result中,並經過set(result)將result保存。
以後調用FutureTask的get()方法,返回的就是經過set(result)保存的值。
更多內容
1. Java多線程系列--「JUC線程池」02之 線程池原理(一)
2. Java多線程系列--「JUC線程池」03之 線程池原理(二)
3. Java多線程系列--「JUC線程池」04之 線程池原理(三)
4. Java多線程系列--「JUC線程池」05之 線程池原理(四)