1. 程式人生 > >java核心-多線程-線程類-Callable、Future和FutureTask

java核心-多線程-線程類-Callable、Future和FutureTask

包裝 示例 概念 return time let thread .sh int

  1. 基本概念
    <1>Callable,Callable和Runnable差不多,兩者都是為那些其實例可能被另一個線程執行的類而設計的,最主要的差別在於Runnable不會
    返回線程運算結果,Callable可以(假如線程需要返回運行結果)。
    <2>Future,是一個接口表示異步計算的結果,它提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。
    <3>FutureTask是Future的實現類,也可以說是進階類,優化了Future的一些缺點,比如Future.get會阻塞等等,它提供了對Future的基本實現。
    可使用FutureTask包裝Callable或Runnable對象,實現異步處理線程運行結果。FutureTask實現了Runnable和Future(看源碼可以看出來),所以也可以

    將FutureTask提交給Executor。一般使用FutureTask代替Future即可。

  2. 使用api

    <1>Callable使用方法

             call()  //類似run()方法

    <2>Future使用方法

             cancel(boolean mayInterruptIfRunning)  //取消任務,如果已經完成,返回false
             isCancelled()    //判斷是否取消過
             isDone()    //判斷是否完成,取消、完成、異常都會返回true
             get()  //獲取執行結果,阻塞的 

    <3>FutureTask使用方法

             cancel(boolean mayInterruptIfRunning)
             isCancelled()
             done()  //重寫它來實現異步處理線程執行結果
             isDone()
             run()
             get()
  3. 使用示例
    Callable+Futrue

    private  static class CallableThread implements Callable<String>{
        @Override
        public String call() throws Exception {
            System.out.println("進入CallableThread的call()方法, 開始睡覺, 睡覺時間為" + System.currentTimeMillis());
            Thread.sleep(10000);
            System.out.println("睡覺結束");
            return "123";
        }
    }

    @Test
    public void test2(){
        ExecutorService executorService = Executors.newCachedThreadPool();
        CallableThread callableThread = new CallableThread();
        long l = System.currentTimeMillis();
        System.out.println("任務提交前時間:" + l);
        Future<String> submit = executorService.submit(callableThread);
        try {
            String s = submit.get();
        }catch (Exception e){
        }
        System.out.println("獲取結果的時間:" + (System.currentTimeMillis()-l));
    }

執行結果

    任務提交前時間:1556438172228
    進入CallableThread的call()方法, 開始睡覺, 睡覺時間為1556438172229
    睡覺結束
    獲取結果的時間:10006

這裏的 Future.get 是阻塞方法 , 會一直等待Callable中線程任務執行完畢,是很低下的效率,
解決方式
1.可以使用FutureTask ,重寫done方法
2.循環判斷isDone,返回true的時候然後調用get()獲取

    Callable+FutureTask,異步處理線程運行結果

    private  static class CallableThread implements Callable<String>{
        @Override
        public String call() throws Exception {
            System.out.println("進入CallableThread的call()方法, 開始睡覺, 睡覺時間為" + System.currentTimeMillis());
            Thread.sleep(10000);
            System.out.println("睡覺結束");
            return "123";
        }
    }
     private class MyFutureTask extends FutureTask<String>{
        public MyFutureTask(Callable callable){
            super(callable);
        }

        //FutureTask任務完成,會回調這個方法
        @Override
        protected void done() {
            System.out.println("執行完調用了done()");
            super.done();
            try {
                String s = this.get();
                System.out.println("任務執行完畢:" + s);
                System.out.println("當前時間:" + System.currentTimeMillis());

            }catch (Exception e){
            }
        }
    }

    @Test
    public  void test3() {
        ExecutorService executorService = Executors.newCachedThreadPool();
        CallableThread callableThread = new CallableThread();
        MyFutureTask myFutureTask = new MyFutureTask(callableThread);
        executorService.submit(myFutureTask);
        System.out.println("主線程執行結束");
        try {
             executorService.shutdown();
            executorService.awaitTermination(12,TimeUnit.SECONDS);
        } catch (Exception e) {
        }finally {
            executorService.shutdownNow();
        }
    }

執行結果

     執行結果如下
                主線程執行結束
                進入CallableThread的call()方法, 開始睡覺, 睡覺時間為1556416923492
                睡覺結束
                執行完調用了done()
                任務執行完畢:123
                當前時間:1556416933493

java核心-多線程-線程類-Callable、Future和FutureTask