[Java并發(fā)編程實戰(zhàn)] Future+callable+FutureTask 閉鎖機制(含示例代碼)

業(yè)精于勤,荒于嬉;行成于思,毀于隨?!n愈
它告訴我們,事業(yè)的成功在于奮發(fā)努力,勤勉進取,太貪玩,放松要求便會一事無成;做事情要想成功,需要反復(fù)思考、深思熟慮,而隨手隨意、隨隨便便行事,做事不經(jīng)過大腦,必然招致失敗。

PS: 如果覺得本文有用的話,請幫忙點贊,留言評論支持一下哦,您的支持是我最大的動力!謝謝啦~

FutureTask 也可以做閉鎖,它是 Future 和 callable 的結(jié)合體。所以我們有必要來了解 FutureTask 這個類。

FutureTask 的繼承關(guān)系類圖

先看 FutureTask 類的繼承:

public class FutureTask<V> implements RunnableFuture<V> 

它繼承自 RunnableFuture,可以看出他是 Runnable 和 Future 的結(jié)合體。

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

我們熟悉的 Runnable 接口:

public interface Runnable {
    public abstract void run();
}

不常見的Future 接口,用來獲取異步計算結(jié)果:

public interface Future<V> {

    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     */
    boolean isCancelled();//如果任務(wù)被取消,返回true

    /**
     * Returns {@code true} if this task completed.
     */
    boolean isDone();//如果任務(wù)執(zhí)行結(jié)束,無論是正常結(jié)束或是中途取消還是發(fā)生異常,都返回true。

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     */
    V get() throws InterruptedException, ExecutionException; //獲取異步執(zhí)行的結(jié)果,如果沒有結(jié)果可用,此方法會阻塞直到異步計算完成。

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

到這里,F(xiàn)utureTask 整個繼承關(guān)系已經(jīng)很清楚了。為了更直觀一點,我用 starUML 畫出它的類繼承關(guān)系圖。

image

在類關(guān)系圖中,我們可以看到 FutureTask 的構(gòu)造函數(shù),包含了之前沒有見過的類型:Callable<T>。我們直接看下它的兩個構(gòu)造函數(shù)實現(xiàn),進一步了解看看:

    //構(gòu)造函數(shù)1
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    //構(gòu)造函數(shù)2
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

這里已經(jīng)非常清楚了,最終都是賦值給 FutureTask 的內(nèi)部變量 callable。它是一個接口,包含一個有返回值的函數(shù) call()。

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

通過上面的講解,我們已經(jīng)知道 Future,FutureTask,Callable,Runnable的關(guān)系了。那么,說了這么多主要是想干嘛呢?

沒錯,主要就是為了線程執(zhí)行完成后能夠返回結(jié)果。我們知道,Runnable 接口執(zhí)行完成后,是沒法返回結(jié)果的。所以,我們?nèi)绻胍軌蚍祷貓?zhí)行的結(jié)果,必須使用 callable 接口。

應(yīng)用場景

比如我們有個耗時的計算操作,現(xiàn)在創(chuàng)建一個子線程執(zhí)行計算操作,主線程通過 FutureTask.get() 的方式獲取計算結(jié)果,如果計算還沒有完成,則會阻塞一直等到計算完成。

下面我們直接編寫代碼來實現(xiàn)上面的應(yīng)用場景。

使用 Callable + FutureTask 獲取執(zhí)行結(jié)果:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class FutureTaskTest{

    //創(chuàng)建一個Future對象,并把Callable的實現(xiàn)傳給構(gòu)造函數(shù)
    private static final FutureTask<Integer> future = new FutureTask<Integer>(new CallableTest());

    public static void main(String[] args) {
        //創(chuàng)建一個線程
        final Thread thread = new Thread(future);
        //啟動線程
        thread.start();
        try {
            Thread.sleep(1000);
            System.out.println("Main thread is running");
            //獲取計算結(jié)果,會阻塞知道計算完畢
            System.out.println("get the sub thread compute result : " + future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("main thread is end");
    }
    
    //實現(xiàn)Callable接口,耗時操作
    static class CallableTest implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            int ret = 0;
            Thread.sleep(1000);
            System.out.println("sub thread is computing");
            for(int i = 0; i < 1000; i++) {
                ret += i;
            }
            System.out.println("sub thread is finish compute");
            return ret;
        }   
    }
}

運行結(jié)果:


image
另外一種方式,是使用 Callable + Future + ExecutorService 的方式。ExecutorService繼承自Executor,它的目的是為我們管理Thread對象,從而簡化并發(fā)編程,Executor使我們無需顯示的去管理線程的生命周期。

在ExecutorService接口中聲明了若干個submit方法的重載版本:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task); 

第一個submit方法里面的參數(shù)類型就是Callable。

示例如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class FutureTaskTest{
    public static void main(String[] args) {
        //返回一個線程池,通常都和這種線程寬架搭配
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        System.out.println("Main thread is running");
        //提交給線程,返回一個Future類,并執(zhí)行
        Future<Integer> future = threadPool.submit(new CallableTest());
        try {
            Thread.sleep(1000);
            //獲取計算結(jié)果,會阻塞知道計算完畢
            System.out.println("get the sub thread compute result : " + future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("main thread is end");
    }
    //實現(xiàn)Callable接口,耗時操作
    static class CallableTest implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            int ret = 0;
            Thread.sleep(1000);
            System.out.println("sub thread is computing");
            for(int i = 0; i < 1000; i++) {
                ret += i;
            }
            System.out.println("sub thread is finish compute");
            return ret;
        }   
    }
}

執(zhí)行結(jié)果


image

本文完結(jié),希望看完對你有幫助,歡迎關(guān)注我~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內(nèi)容