Future 解析與使用

Java 1.5開始, 提供了 CallableFuture, 通過它們可以在任務執行完畢之後得到任務執行結果.

當需要調用幾個執行很慢的方法時, 可以使用多線程一起執行這幾個方法, 等所有方法執行完畢後得到執行結果, 在進行別的處理.

Future 的主要方法

Future 接口主要包括 5 個方法:

clipboard.png

get() 方法可以當任務結束後返回一個結果, 如果調用時, 工作還沒有結束, 則會阻塞線程, 直到任務執行完畢.

get(long timeout,TimeUnit unit) 做多等待 timeout 的時間就會返回結果.

cancel(boolean mayInterruptIfRunning) 方法可以用來停止一個任務.

isDone() 方法判斷當前方法是否完成.

isCancel() 方法判斷當前方法是否取消.

Future 示例 demo

需求場景: 等早餐過程中, 包子需要 3 秒, 涼菜需要 1 秒, 普通的多線程需要四秒才能完成. 先等涼菜, 再等包子, 因爲等涼菜時, 普通多線程啓動 start() 方法, 執行 run() 中具體方法時, 沒有返回結果, 所以如果要等有返回結果, 必須是要1秒結束後才知道結果.

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();

        // 等涼菜 
        Callable ca1 = new Callable() {
            @Override
            public String call() throws Exception {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "涼菜準備完畢";
            }
        };
        FutureTask<String> ft1 = new FutureTask<String>(ca1);
        new Thread(ft1).start();

        // 等包子 -- 必須要等待返回的結果,所以要調用join方法
        Callable ca2 = new Callable() {

            @Override
            public Object call() throws Exception {
                try {
                    Thread.sleep(1000 * 3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "包子準備完畢";
            }
        };
        FutureTask<String> ft2 = new FutureTask<String>(ca2);
        new Thread(ft2).start();

        System.out.println(ft1.get());
        System.out.println(ft2.get());

        long end = System.currentTimeMillis();
        System.out.println("準備完畢時間:" + (end - start));
    }

還有一個比較典型的例子就是設置超時時間:

    //固定大小的線程池,同時只能接受5個任務
    static ExecutorService mExecutor = Executors.newFixedThreadPool(5);
    final static long timeout = 4 ;

    /**
     * 模擬在預定時間內獲取廣告信息
     * @throws InterruptedException
     */
    static void rederPageWithAd(final String pageTitle)  throws  InterruptedException{
        Future<String> f = mExecutor.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("開始加載廣告信息");
                int randomTime = new Random().nextInt(5) + 1;//限制耗時不會出現0s,不會大於10s
                Thread.sleep(100 * 1000);
                System.out.println("正常加載廣告耗時:" + randomTime +"s");
                return pageTitle;
            }
        });

        String page;
        try {
            //在預計時間內等待
            System.out.println("預期任務執行完時間:" + timeout + "s");
            //page = f.get();
            page = f.get(timeout, TimeUnit.SECONDS);
        } catch (ExecutionException e) {
            page = "出現執行異常,顯示默認的廣告頁面";
        } catch (TimeoutException e) {
            page = "任務執行超時,顯示默認的廣告頁面";
            f.cancel(true);//取消沒有執行完的任務,設置爲ture說明任務能被中斷,否則執行中的任務要完成
        }
        System.out.println("成功加載廣告頁面:" + page);


    }


    public static void main(String[] args) {
        try {
            List<String> titleList = new ArrayList<String>();
            titleList.add("體育賽事");
            titleList.add("娛樂新聞");
            titleList.add("實時聚焦");
            titleList.add("國際諮詢");
            titleList.add("影視天下");
            titleList.add("遊戲風雲");
            for (String string : titleList) {
                rederPageWithAd(string);
            }

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally{
            /**
             * 只有執行了shutdown方法,執行isTerminated纔有效。否則isTerminated一直爲ture
             */
            mExecutor.shutdown();
            while(true){
                if(mExecutor.isTerminated()){
                    System.out.println("所有任務都執行完了,關閉線程池");
                    break;
                }
            }
        }

    }

值得注意的是: 當主線程調用 Futureget 方法的時候會獲取到從線程中返回的結果數據. 如果在線程的執行過程中發生了異常, get 會獲取到異常的信息.

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