中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Callable、Future和FutureTask的作用分別是什么

發布時間:2021-06-22 14:39:18 來源:億速云 閱讀:224 作者:chen 欄目:大數據

這篇文章主要介紹“Callable、Future和FutureTask的作用分別是什么”,在日常操作中,相信很多人在Callable、Future和FutureTask的作用分別是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Callable、Future和FutureTask的作用分別是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

1.Callable<V>接口
我們先回顧一下java.lang.Runnable接口,就聲明了run(),其返回值為void,當然就無法獲取結果了。
public interface Runnable {
    public abstract void run();
}
而Callable的接口定義如下
public interface Callable<V> { 
      V   call()   throws Exception; 

該接口聲明了一個名稱為call()的方法,同時這個方法可以有返回值V,也可以拋出異常。嗯,對該接口我們先了解這么多就行,下面我們來說明如何使用,前篇文章我們說過,無論是Runnable接口的實現類還是Callable接口的實現類,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執行,ThreadPoolExecutor或ScheduledThreadPoolExecutor都實現了ExcutorService接口,而因此Callable需要和Executor框架中的ExcutorService結合使用,我們先看看ExecutorService提供的方法:
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
第一個方法:submit提交一個實現Callable接口的任務,并且返回封裝了異步計算結果的Future。
第二個方法:submit提交一個實現Runnable接口的任務,并且指定了在調用Future的get方法時返回的result對象。
第三個方法:submit提交一個實現Runnable接口的任務,并且返回封裝了異步計算結果的Future。
因此我們只要創建好我們的線程對象(實現Callable接口或者Runnable接口),然后通過上面3個方法提交給線程池去執行即可。還有點要注意的是,除了我們自己實現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>接口是用來獲取異步計算結果的,說白了就是對具體的Runnable或者Callable對象任務執行的結果進行獲取(get()),取消(cancel()),判斷是否完成等操作。我們看看Future接口的源碼:
public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
方法解析:
V get() :獲取異步執行的結果,如果沒有結果可用,此方法會阻塞直到異步計算完成。
V get(Long timeout , TimeUnit unit) :獲取異步執行結果,如果沒有結果可用,此方法會阻塞,但是會有時間限制,如果阻塞時間超過設定的timeout時間,該方法將拋出異常。
boolean isDone() :如果任務執行結束,無論是正常結束或是中途取消還是發生異常,都返回true。
boolean isCanceller() :如果任務完成前被取消,則返回true。
boolean cancel(boolean mayInterruptRunning) :如果任務還沒開始,執行cancel(...)方法將返回false;如果任務已經啟動,執行cancel(true)方法將以中斷執行此任務線程的方式來試圖停止任務,如果停止成功,返回true;當任務已經啟動,執行cancel(false)方法將不會對正在執行的任務線程產生影響(讓線程正常執行到完成),此時返回false;當任務已經完成,執行cancel(...)方法將返回false。mayInterruptRunning參數表示是否中斷執行中的線程。
通過方法分析我們也知道實際上Future提供了3種功能:(1)能夠中斷執行中的任務(2)判斷任務是否執行完成(3)獲取任務執行完成后額結果。
但是我們必須明白Future只是一個接口,我們無法直接創建對象,因此就需要其實現類FutureTask登場啦。
3.FutureTask類
我們先來看看FutureTask的實現
public class FutureTask<V> implements RunnableFuture<V> {
FutureTask類實現了RunnableFuture接口,我們看一下RunnableFuture接口的實現:
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
分析:FutureTask除了實現了Future接口外還實現了Runnable接口,因此FutureTask也可以直接提交給Executor執行。 當然也可以調用線程直接執行(FutureTask.run())。接下來我們根據FutureTask.run()的執行時機來分析其所處的3種狀態:
(1)未啟動,FutureTask.run()方法還沒有被執行之前,FutureTask處于未啟動狀態,當創建一個FutureTask,而且沒有執行FutureTask.run()方法前,這個FutureTask也處于未啟動狀態。
(2)已啟動,FutureTask.run()被執行的過程中,FutureTask處于已啟動狀態。
(3)已完成,FutureTask.run()方法執行完正常結束,或者被取消或者拋出異常而結束,FutureTask都處于完成狀態。

下面我們再來看看FutureTask的方法執行示意圖(方法和Future接口基本是一樣的,這里就不過多描述了)

分析:
(1)當FutureTask處于未啟動或已啟動狀態時,如果此時我們執行FutureTask.get()方法將導致調用線程阻塞;當FutureTask處于已完成狀態時,執行FutureTask.get()方法將導致調用線程立即返回結果或者拋出異常。
(2)當FutureTask處于未啟動狀態時,執行FutureTask.cancel()方法將導致此任務永遠不會執行。
當FutureTask處于已啟動狀態時,執行cancel(true)方法將以中斷執行此任務線程的方式來試圖停止任務,如果任務取消成功,cancel(...)返回true;但如果執行cancel(false)方法將不會對正在執行的任務線程產生影響(讓線程正常執行到完成),此時cancel(...)返回false。
當任務已經完成,執行cancel(...)方法將返回false。
最后我們給出FutureTask的兩種構造函數:
public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}
3.Callable<V>/Future<V>/FutureTask的使用
通過上面的介紹,我們對Callable,Future,FutureTask都有了比較清晰的了解了,那么它們到底有什么用呢?我們前面說過通過這樣的方式去創建線程的話,最大的好處就是能夠返回結果,加入有這樣的場景,我們現在需要計算一個數據,而這個數據的計算比較耗時,而我們后面的程序也要用到這個數據結果,那么這個時Callable豈不是最好的選擇?我們可以開設一個線程去執行計算,而主線程繼續做其他事,而后面需要使用到這個數據時,我們再使用Future獲取不就可以了嗎?下面我們就來編寫一個這樣的實例
3.1 使用Callable+Future獲取執行結果
Callable實現類如下:
package com.zejian.Executor;
import java.util.concurrent.Callable;
/**
 * @author zejian
 * @time 2016年3月15日 下午2:02:42
 * @decrition Callable接口實例
 */
public class CallableDemo implements Callable<Integer> {
    
    private int sum;
    @Override
    public Integer call() throws Exception {
        System.out.println("Callable子線程開始計算啦!");
        Thread.sleep(2000);
        
        for(int i=0 ;i<5000;i++){
            sum=sum+i;
        }
        System.out.println("Callable子線程計算結束!");
        return sum;
    }
}
Callable執行測試類如下:

package com.zejian.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * @author zejian
 * @time 2016年3月15日 下午2:05:43
 * @decrition callable執行測試類
 */
public class CallableTest {
    
    public static void main(String[] args) {
        //創建線程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        //創建Callable對象任務
        CallableDemo calTask=new CallableDemo();
        //提交任務并獲取執行結果
        Future<Integer> future =es.submit(calTask);
        //關閉線程池
        es.shutdown();
        try {
            Thread.sleep(2000);
        System.out.println("主線程在執行其他任務");
        
        if(future.get()!=null){
            //輸出獲取到的結果
            System.out.println("future.get()-->"+future.get());
        }else{
            //輸出獲取到的結果
            System.out.println("future.get()未獲取到結果");
        }
        
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主線程在執行完成");
    }
}
執行結果:
Callable子線程開始計算啦!
主線程在執行其他任務
Callable子線程計算結束!
future.get()-->12497500
主線程在執行完成
3.2 使用Callable+FutureTask獲取執行結果
package com.zejian.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
 * @author zejian
 * @time 2016年3月15日 下午2:05:43
 * @decrition callable執行測試類
 */
public class CallableTest {
    
    public static void main(String[] args) {
//        //創建線程池
//        ExecutorService es = Executors.newSingleThreadExecutor();
//        //創建Callable對象任務
//        CallableDemo calTask=new CallableDemo();
//        //提交任務并獲取執行結果
//        Future<Integer> future =es.submit(calTask);
//        //關閉線程池
//        es.shutdown();
        
        //創建線程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        //創建Callable對象任務
        CallableDemo calTask=new CallableDemo();
        //創建FutureTask
        FutureTask<Integer> futureTask=new FutureTask<>(calTask);
        //執行任務
        es.submit(futureTask);
        //關閉線程池
        es.shutdown();
        try {
            Thread.sleep(2000);
        System.out.println("主線程在執行其他任務");
        
        if(futureTask.get()!=null){
            //輸出獲取到的結果
            System.out.println("futureTask.get()-->"+futureTask.get());
        }else{
            //輸出獲取到的結果
            System.out.println("futureTask.get()未獲取到結果");
        }
        
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主線程在執行完成");
    }
}
執行結果:
Callable子線程開始計算啦!
主線程在執行其他任務
Callable子線程計算結束!
futureTask.get()-->12497500
主線程在執行完成

到此,關于“Callable、Future和FutureTask的作用分別是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

易门县| 博乐市| 南部县| 旬阳县| 淳化县| 巴青县| 商城县| 通州市| 永靖县| 乐昌市| 辽宁省| 水城县| 铁岭县| 当雄县| 敦化市| 屯门区| 通河县| 鄂托克旗| 沙坪坝区| 沁阳市| 航空| 丹寨县| 尼玛县| 巩留县| 乐安县| 来安县| 婺源县| 邵武市| 女性| 彰化市| 东方市| 神农架林区| 双峰县| 上饶县| 云林县| 仙桃市| 巴彦淖尔市| 突泉县| 南雄市| 平乡县| 科技|