FutureTask、Callable 實現(xiàn)線程結(jié)果返回

簡介

創(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)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容