簡介
創(chuàng)建線程的方式有兩種,一種是實現(xiàn)Runnable接口,另一種是繼承Thread。但是這兩種方式都有個缺點,那就是在任務(wù)執(zhí)行完成之后無法獲取返回結(jié)果。
那如果我們想要獲取返回結(jié)果該如何實現(xiàn)呢?
Executor框架結(jié)構(gòu)中提到的Callable接口和Future接口,從Java SE 5.0開始引入了Callable和Future,通過它們構(gòu)建的線程,在任務(wù)執(zhí)行完成后就可以獲取執(zhí)行結(jié)果。
1.runnable接口與callable接口比較
Runnable:
public interface Runnable {
public abstract void run();
}
Callable:
public interface Callable<V> {
V call() throws Exception;
}
Callable介紹
該接口聲明了一個名稱為call()的方法,同時這個方法可以有返回值V,也可以拋出異常。下面我們來說明如何使用,無論是Runnable接口的實現(xiàn)類還是Callable接口的實現(xiàn)類,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執(zhí)行,ThreadPoolExecutor或ScheduledThreadPoolExecutor都實現(xiàn)了ExcutorService接口,而因此Callable需要和Executor框架中的ExcutorService結(jié)合使用,我們先看看ExecutorService提供的方法:
<T> Future<T> submit(Callable<T> task); //submit提交一個實現(xiàn)Callable接口的任務(wù),并且返回封裝了異步計算結(jié)果的Future。
<T> Future<T> submit(Runnable task, T result); //submit提交一個實現(xiàn)Runnable接口的任務(wù),并且指定了在調(diào)用Future的get方法時返回的result對象。
Future<?> submit(Runnable task); //submit提交一個實現(xiàn)Runnable接口的任務(wù),并且返回封裝了異步計算結(jié)果的Future。
其他方法
還有點要注意的是,除了我們自己實現(xiàn)Callable對象外,我們還可以使用工廠類Executors來把一個Runnable對象包裝成Callable對象。Executors工廠類提供的方法如下:
public static Callable<Object> callable(Runnable task)
public static <T> Callable<T> callable(Runnable task, T result)
2.Future<V>接口
Future<V>接口是用來獲取異步計算結(jié)果的,說白了就是對具體的Runnable或者Callable對象任務(wù)執(zhí)行的結(jié)果進行獲取(get()),取消(cancel()),判斷是否完成等操作。
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning); //如果任務(wù)還沒開始,執(zhí)行cancel(...)方法將返回false;如果任務(wù)已經(jīng)啟動,執(zhí)行cancel(true)方法將以中斷執(zhí)行此任務(wù)線程的方式來試圖停止任務(wù),如果停止成功,返回true;當(dāng)任務(wù)已經(jīng)啟動,執(zhí)行cancel(false)方法將不會對正在執(zhí)行的任務(wù)線程產(chǎn)生影響(讓線程正常執(zhí)行到完成),此時返回false;當(dāng)任務(wù)已經(jīng)完成,執(zhí)行cancel(...)方法將返回false。mayInterruptRunning參數(shù)表示是否中斷執(zhí)行中的線程。
boolean isCancelled(); //如果任務(wù)完成前被取消,則返回true。
boolean isDone(); //如果任務(wù)執(zhí)行結(jié)束,無論是正常結(jié)束或是中途取消還是發(fā)生異常,都返回true
V get() throws InterruptedException, ExecutionException; //獲取異步執(zhí)行的結(jié)果,如果沒有結(jié)果可用,此方法會阻塞直到異步計算完成。
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; //獲取異步執(zhí)行結(jié)果,如果沒有結(jié)果可用,此方法會阻塞,但是會有時間限制,如果阻塞時間超過設(shè)定的timeout時間,該方法將返回null。
}
總結(jié):
實際上Future提供了3種功能:
- 能夠中斷執(zhí)行中的任務(wù);
- 判斷任務(wù)是否執(zhí)行完成;
- 獲取任務(wù)執(zhí)行完成后額結(jié)果;
但是Future只是一個接口,如果想要使用的話需要使用它的實現(xiàn)類FutureTask。
3.FutureTask
public class FutureTask<V> implements RunnableFuture<V> {
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
分析:
FutureTask除了實現(xiàn)了Future接口外還實現(xiàn)了Runnable接口,因此FutureTask也可以直接提交給Executor執(zhí)行。當(dāng)然也可以調(diào)用線程直接執(zhí)行(FutureTask.run())。接下來我們根據(jù)FutureTask.run()的執(zhí)行時機來分析其所處的3種狀態(tài):
- 未啟動,F(xiàn)utureTask.run()方法還沒有被執(zhí)行之前,F(xiàn)utureTask處于未啟動狀態(tài),當(dāng)創(chuàng)建一個FutureTask,而且沒有執(zhí)行FutureTask.run()方法前,這個FutureTask也處于未啟動狀態(tài)。
- 已啟動,F(xiàn)utureTask.run()被執(zhí)行的過程中,F(xiàn)utureTask處于已啟動狀態(tài)。
- 已完成,F(xiàn)utureTask.run()方法執(zhí)行完正常結(jié)束,或者被取消或者拋出異常而結(jié)束,F(xiàn)utureTask都處于完成狀態(tài)。