【java】獲取線程池中的線程返回結果,Future和FutureTask的使用

本文會結合Future描述下線程池的使用場景

最近因爲換了工作,新工作需要更多的時間熟悉和上手,所以好久沒有寫文章了!

不過其實也一直有在看一些東西,比如Netty,spark源碼(其實以前有看過,但是太囫圇吞棗忘得差不多了) ,然後想起我以前寫過一個線程池相關的文章,但是對於線程池的使用只是一筆帶過,所以今天想具體來寫寫

 

【java】線程池概念,如何使用線程池?:https://blog.csdn.net/lsr40/article/details/101428779

 

案例:

曾經做過這麼一個案例,就是通過用戶傳入的參數,實時構建一份數據報表,這個功能肯定是異步的,相當於用戶調用了一個create方法把參數傳入進來,就直接返回了,不過後臺會啓動第一個線程池,來根據獲得的參數實際查數據庫,創建數據報表,保存到數據庫,然後又啓動了一個線程池(回調方法),這個線程池裏面使用了Future的get方法來等待第一個線程池完畢,並且將create的記錄修改爲成功或者失敗,並且記錄相關原因! 

話不多說!下面,我會用六個例子,來演示Future的用法(我上面說的案例,用的是第五種模型,只不過FutureTask我們又自己封裝了一層,在裏面做了時間的記錄,日誌的打印,或者一些前置的初始化操作等待)

代碼示例:

package com.study.asyn;

import java.util.concurrent.*;

/**
 * Created with IntelliJ IDEA
 * Description:
 * User: lsr
 * Date: 2020/6/15
 * Time: 18:46
 */
public class FutureTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        System.out.println("主線程開始工作:");
        long startTime = System.currentTimeMillis();
        ExecutorService executorService = Executors.newFixedThreadPool(1);

        //newThreadDemo(executorService);
        //futureGetDemo(executorService);
        //futureGetAndTimeOutDemo(executorService);
        //futureGetAndCallableDemo(executorService);
        //callbackDemo(executorService);
        futureTaskDemo(executorService);

        long stopTime = System.currentTimeMillis();
        System.out.println("主線程結束,耗時:"+(stopTime - startTime)+"ms");
        //關閉線程
        executorService.shutdown();
    }

    /**
     *  第一種,無所謂線程執行是否結束,不阻塞
     *      打印結果:
     *      主線程開始工作:
     *      主線程結束,耗時:3ms
     *      線程中的任務,開始運行!
     *      正在執行!
     *      線程中的任務,結束執行!
     * @param executorService
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void newThreadDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
        executorService.submit(new Runnable() {
            public void run() {
                System.out.println("線程中的任務,開始運行!");
                doSomeThing();
                System.out.println("線程中的任務,結束執行!");
            }
        });
    }


    /**
     *  第二種,通過future的get方法,會阻塞等到執行完畢!
     *      主線程開始工作:
     *      線程中的任務,開始運行!
     *      正在執行!
     *      線程中的任務,結束執行!
     *      null
     *      主線程結束,耗時:3005ms
     * @param executorService
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void futureGetDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
        Future<?> future = executorService.submit(new Runnable() {
            public void run() {
                System.out.println("線程中的任務,開始運行!");
                doSomeThing();
                System.out.println("線程中的任務,結束執行!");
            }
        });
        Object o = future.get();
        System.out.println(o);
    }

    /**
     *  第三種,通過future的get方法,並且有超時時間,會阻塞等到執行完畢!
     *
     *      主線程開始工作:
     *      線程中的任務,開始運行!
     *      正在執行!
     *      主線程結束,耗時:1007ms
     *      java.util.concurrent.TimeoutException
     * 	        at java.util.concurrent.FutureTask.get(FutureTask.java:205)
     * 	        at com.study.asyn.FutureTest.futureGetAndTimeOutDemo(FutureTest.java:99)
     * 	        at com.study.asyn.FutureTest.main(FutureTest.java:21)
     *      線程中的任務,結束執行!
     * @param executorService
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void futureGetAndTimeOutDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
        Future<?> future = executorService.submit(new Runnable() {
            public void run() {
                System.out.println("線程中的任務,開始運行!");
                doSomeThing();
                System.out.println("線程中的任務,結束執行!");
            }
        });
        Object o = null;
        try {
            o = future.get(1,TimeUnit.SECONDS);
            System.out.println(o);
        } catch (TimeoutException e) {
            //true和false的區別大家可以看源碼中的註釋
            //true就是中斷當前執行的線程,false就是讓線程執行完
            future.cancel(false);
            e.printStackTrace();
        }

    }


    /**
     *  第四種,通過future的get並且配合Callable方法,獲得線程中return結果,會阻塞等到執行完畢!
     *      主線程開始工作:
     *      線程中的任務,開始運行!
     *      正在執行!
     *      線程中的任務,結束執行!
     *      返回值~
     *      主線程結束,耗時:3005ms
     * @param executorService
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void futureGetAndCallableDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
        Future<?> future = executorService.submit(new Callable<String>() {
            public String call() throws Exception {
                System.out.println("線程中的任務,開始運行!");
                doSomeThing();
                System.out.println("線程中的任務,結束執行!");
                return "返回值~";
            }
        });
        String returnValue = (String)future.get();
        System.out.println(returnValue);
    }

    /**
     *  第五種,想在獲得future的get結果之後,再做一些處理,但是又不想阻塞主線程,通過回調,啓動另一個線程來做這個事情
     *
     *      主線程開始工作:
     *      線程中的任務,開始運行!
     *      正在執行!
     *      主線程結束,耗時:5ms
     *      線程中的任務,結束執行!
     *      返回值~
     *      成功!
     *
     * @param executorService
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void callbackDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
        ExecutorService fixExecutorService = Executors.newFixedThreadPool(1);

        final Future<?> future = executorService.submit(new Callable<String>() {
            public String call() throws Exception {
                System.out.println("線程中的任務,開始運行!");
                doSomeThing();
                System.out.println("線程中的任務,結束執行!");
                return "返回值~";
            }
        });

        fixExecutorService.submit(new Runnable() {
            public void run() {
                String returnValue = null;
                try {
                    returnValue = (String)future.get();
                    System.out.println(returnValue);
                    System.out.println("成功!");
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });
        fixExecutorService.shutdown();

    }


    /**
     *  第六種,之前線程都是使用submit提交任務,以此獲得返回Future對象
     *  但是使用升級版的FutureTask+線程池的execute方法,也能得到返回值
     *
     *      主線程開始工作:
     *      線程中的任務,開始運行!
     *      正在執行!
     *      線程中的任務,結束執行!
     *      返回值~
     *      主線程結束,耗時:3005ms
     *
     * @param executorService
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void futureTaskDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
            public String call() throws Exception {
                System.out.println("線程中的任務,開始運行!");
                doSomeThing();
                System.out.println("線程中的任務,結束執行!");
                return "返回值~";
            }
        });
        //execute方法雖然沒有返回值,但是因爲FutureTask實現類Future+Runnable,
        // 所以也可以直接調用execute方法計算,再調用get獲得返回結果
        executorService.execute(futureTask);
        String s = futureTask.get();
        System.out.println(s);

    }


    private static void doSomeThing(){
        try {
            System.out.println("正在執行!");
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

結語:

好了,沒有什麼多餘的東西要在這篇文章裏說明了(每一種方法我都寫好了註釋,我也都跑過了,沒什麼問吐),大家要是有什麼疑問,歡迎留言!

 

菜雞一隻,努力提升,學習中!!

剛開始工作的時候,覺得有些人做一些朝九晚五不過錢少的工作,看起來一點都不nice,實際自己工作了幾年之後,認真想想那樣的生活又何嘗不痛快呢?大家都在享受人生,千人千面,有人因爲工作有所成就而快樂,有人因爲愛好有所精進而快樂,有人因爲教書育人而快樂,又有人因爲遊戲漲段而快樂,其實只要收入能夠維持自己物質上支出,那做什麼又有什麼區別呢?並沒有那麼多人想在工作中,實現自己的理想和抱負,完成個人價值的昇華。

想起初中語文老師問我,以後的目標是什麼?

讀好書,做好人,生好下一代,培養之,那這輩子的使命不也算完成了?

有時候躺在草地上,呆呆的望向天空,輕柔的雲朵,綿綿的細雨,徜徉在花海中,感受大自然高山流水,又何嘗不是一種人生哲學呢?

下班了,溜了溜了!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章