FutureTask详解

FutureTask用来解决什么问题的? 为什么会出现?

FutureTask为Future接口提供了基础实现,可以用来获取异步任务的返回结果,或者取消异步任务的执行等。

FutureTask如何用?

  1. 定义Task类,继承Callable接口,实现call方法
  2. 新建FutureTask实例,将步骤1中的Task类实例作为构造函数参数传入
  3. 新建Thread对象,将步骤2中的FutureTask实例作为构造函数参数传入
  4. 启动Thread,异步执行任务
  5. 通过FutureTask实例的get、cancel等方法来获取结果或取消执行

示例代码如下:

package org.example.app;

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

public class CallDemo {

    // 1. 继承Callable接口,实现call()方法,泛型参数为要返回的类型
    static class Task implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("Thread [" + Thread.currentThread().getName() + "] is running");
            int result = 0;
            for(int i = 0; i < 100;++i) {
                result += i;
            }

            Thread.sleep(3000);
            return result;
        }
    }

    public static void main(String[] args) {
        /**
         * 第一种方式:Future + ExecutorService
         * Task task = new Task();
         * ExecutorService service = Executors.newCachedThreadPool();
         * Future<Integer> future = service.submit(task1);
         * service.shutdown();
         */


        /**
         * 第二种方式: FutureTask + ExecutorService
         * ExecutorService executor = Executors.newCachedThreadPool();
         * Task task = new Task();
         * FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
         * executor.submit(futureTask);
         * executor.shutdown();
         */

        /**
         * 第三种方式:FutureTask + Thread
         */

        // 2. 新建FutureTask,需要一个实现了Callable接口的类的实例作为构造函数参数
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Task());
        // 3. 新建Thread对象并启动
        Thread thread = new Thread(futureTask);
        thread.setName("Task thread");
        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Thread [" + Thread.currentThread().getName() + "] is running");

        // 4. 调用isDone()判断任务是否结束
        if(!futureTask.isDone()) {
            System.out.println("Task is not done");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int result = 0;
        try {
            // 5. 调用get()方法获取任务结果,如果任务没有执行完成则阻塞等待
            result = futureTask.get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("result is " + result);
    }
}

FutureTask类关系

FutureTask相关类图.png

实现原理

FutureTask相关时序图.png
  1. 调用get()方法时,会将当前线程加入到FutureTask的等待队列中,并调用LockSupport.park()方法对其进行阻塞。
  2. 调用run()方法时,任务执行完成后,将结果赋值给outcome,然后调用LockSupport.unpark()方法唤醒等待队列中阻塞的线程,然后清空等待队列。
  3. 当阻塞的线程被唤醒后,会将outcome作为返回值进行返回。
  4. 带有超时机制的get()方法,是通过调用LockSupport.parkNanos()方法实现超时等待的。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容