Java concurrency線程池之Callable和Future_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Callable 和 Future 簡介
Callable 和 Future 是比較有趣的一對組合。當(dāng)我們需要獲取線程的執(zhí)行結(jié)果時(shí),就需要用到它們。Callable用于產(chǎn)生結(jié)果,F(xiàn)uture用于獲取結(jié)果。
1. Callable
Callable 是一個(gè)接口,它只包含一個(gè)call()方法。Callable是一個(gè)返回結(jié)果并且可能拋出異常的任務(wù)。
為了便于理解,我們可以將Callable比作一個(gè)Runnable接口,而Callable的call()方法則類似于Runnable的run()方法。
Callable的源碼如下:
public interface Callable<V> { V call() throws Exception; }
說明:從中我們可以看出Callable支持泛型。
2. Future
Future 是一個(gè)接口。它用于表示異步計(jì)算的結(jié)果。提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并獲取計(jì)算的結(jié)果。
Future的源碼如下:
public interface Future<V> { // 試圖取消對此任務(wù)的執(zhí)行。 boolean cancel(boolean mayInterruptIfRunning) // 如果在任務(wù)正常完成前將其取消,則返回 true。 boolean isCancelled() // 如果任務(wù)已完成,則返回 true。 boolean isDone() // 如有必要,等待計(jì)算完成,然后獲取其結(jié)果。 V get() throws InterruptedException, ExecutionException; // 如有必要,最多等待為使計(jì)算完成所給定的時(shí)間之后,獲取其結(jié)果(如果結(jié)果可用)。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
說明: Future用于表示異步計(jì)算的結(jié)果。它的實(shí)現(xiàn)類是FutureTask,在講解FutureTask之前,我們先看看Callable, Future, FutureTask它們之間的關(guān)系圖,如下:
說明:
(01) RunnableFuture是一個(gè)接口,它繼承了Runnable和Future這兩個(gè)接口。RunnableFuture的源碼如下:
public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }
(02) FutureTask實(shí)現(xiàn)了RunnableFuture接口。所以,我們也說它實(shí)現(xiàn)了Future接口。
示例和源碼分析(基于JDK1.7.0_40)
我們先通過一個(gè)示例看看Callable和Future的基本用法,然后再分析示例的實(shí)現(xiàn)原理。
import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutionException; class MyCallable implements Callable { @Override public Integer call() throws Exception { int sum = 0; // 執(zhí)行任務(wù) for (int i=0; i<100; i++) sum += i; //return sum; return Integer.valueOf(sum); } } public class CallableTest1 { public static void main(String[] args) throws ExecutionException, InterruptedException{ //創(chuàng)建一個(gè)線程池 ExecutorService pool = Executors.newSingleThreadExecutor(); //創(chuàng)建有返回值的任務(wù) Callable c1 = new MyCallable(); //執(zhí)行任務(wù)并獲取Future對象 Future f1 = pool.submit(c1); // 輸出結(jié)果 System.out.println(f1.get()); //關(guān)閉線程池 pool.shutdown(); } }
運(yùn)行結(jié)果:
4950
結(jié)果說明:
在主線程main中,通過newSingleThreadExecutor()新建一個(gè)線程池。接著創(chuàng)建Callable對象c1,然后再通過pool.submit(c1)將c1提交到線程池中進(jìn)行處理,并且將返回的結(jié)果保存到Future對象f1中。然后,我們通過f1.get()獲取Callable中保存的結(jié)果;最后通過pool.shutdown()關(guān)閉線程池。
1. submit()
submit()在java/util/concurrent/AbstractExecutorService.java中實(shí)現(xiàn),它的源碼如下:
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); // 創(chuàng)建一個(gè)RunnableFuture對象 RunnableFuture<T> ftask = newTaskFor(task); // 執(zhí)行“任務(wù)ftask” execute(ftask); // 返回“ftask” return ftask; }
說明:submit()通過newTaskFor(task)創(chuàng)建了RunnableFuture對象ftask。它的源碼如下:
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); }
2. FutureTask的構(gòu)造函數(shù)
FutureTask的構(gòu)造函數(shù)如下:
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); // callable是一個(gè)Callable對象 this.callable = callable; // state記錄FutureTask的狀態(tài) this.state = NEW; // ensure visibility of callable }
3. FutureTask的run()方法
我們繼續(xù)回到submit()的源碼中。
在newTaskFor()新建一個(gè)ftask對象之后,會(huì)通過execute(ftask)執(zhí)行該任務(wù)。此時(shí)ftask被當(dāng)作一個(gè)Runnable對象進(jìn)行執(zhí)行,最終會(huì)調(diào)用到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中實(shí)現(xiàn),源碼如下:
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 { // 執(zhí)行Callable的call()方法,并保存結(jié)果到result中。 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } // 如果運(yùn)行成功,則將result保存 if (ran) set(result); } } finally { runner = null; // 設(shè)置“state狀態(tài)標(biāo)記” int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
說明:run()中會(huì)執(zhí)行Callable對象的call()方法,并且最終將結(jié)果保存到result中,并通過set(result)將result保存。
之后調(diào)用FutureTask的get()方法,返回的就是通過set(result)保存的值。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JUnit測試控制@Test執(zhí)行順序的三種方式小結(jié)
這篇文章主要介紹了JUnit測試控制@Test執(zhí)行順序的三種方式小結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09springboot無法跳轉(zhuǎn)頁面的問題解決方案
這篇文章主要介紹了springboot無法跳轉(zhuǎn)頁面的問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09SpringBoot?AOP?@Pointcut切入點(diǎn)表達(dá)式排除某些類方式
這篇文章主要介紹了SpringBoot?AOP?@Pointcut切入點(diǎn)表達(dá)式排除某些類方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java Swing JToggleButton開關(guān)按鈕的實(shí)現(xiàn)
這篇文章主要介紹了Java Swing JToggleButton開關(guān)按鈕的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12java開發(fā)工作中對InheritableThreadLocal使用思考
這篇文章主要為大家介紹了java開發(fā)工作中對InheritableThreadLocal使用思考詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11面試官:Java中new Object()到底占用幾個(gè)字節(jié)
這篇文章主要介紹了面試官:Java中new Object()到底占用幾個(gè)字節(jié),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02