Java 異步調用及Callable, Future, FutureTask 原理

一 、使用方式一般爲兩種:

1 . 創建線程執行FutureTask並通過FutureTask得到異步結果;

public static void main(String[] args) throws ExecutionException, InterruptedException {

        long start = System.currentTimeMillis();

        // 1.創建任務,這個FutureTask可以是Callable的也可以是Runnable的
        FutureTask task = new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(3000); // 模擬異步任務執行
                return "我是異步結果";
            }
        });

        // 2.創建線程執行任務
        Thread thread = new Thread(task);
        thread.start();

        // 3.主線程模擬在異步任務之間執行其他任務
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 4.得到異步任務結果
        System.out.println(task.get());

        System.out.println("運行時間 : " + (System.currentTimeMillis() - start) + "ms");
    }

運行結果:

我是異步結果
運行時間 : 6002ms

Process finished with exit code 0

 

2 . 使用線程池管理線程通過Future接口得到結果;

public static void main(String[] args) throws ExecutionException, InterruptedException {

        long start = System.currentTimeMillis();

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        Future future = executorService.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(3000);
                return "我是異步結果";
            }
        });

        System.out.println("主線程工作");
        Thread.sleep(6000);

        System.out.println(future.get());

        System.out.println("運行時間 : " + (System.currentTimeMillis() - start) + "ms");
    }

 運行結果:

主線程工作
我是異步結果
運行時間 : 6012ms 

 

注意:

        異步結果用Future或者FutureTask都可以獲取。Future是接口,FutureTask是實現了這個接口的實現類。FutureTask除了實現Future接口外,還實現了Runnable接口。所以不論是Callable任務還是Runnable任務都可以用FutureTask完成,而這兩種都會最終都會調用Callable的call方法,對於Runnable實現調用call的方式是使用了適配器模式。

 (圖片來源網上,侵刪)

      debug第二個程序,我們可以看到這時定義的Future也是FutureTask實現的。

二、異步原理

1.  異步模型:

         可以總結爲生產者和消費者,生產者就是線程處理任務,消費者就是調用者得到任務結果。那生產者消費者模型還有緩衝區啊,這裏面就是用FutureTask中的outcome字段在任務結束後緩存結果。

2 . 異步流程:

         主線程main開啓線程a執行任務,並馬上返回Future,如果是剛新建任務,狀態置爲new。當main線程想取線程a執行的結果(調用了FutureTask的get方法)時,就查看這個任務的state是否執行完成(completing),如果還沒有完成就阻塞當前線程(main)等待線程a執行完成。

 

 

 

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