从源码剖析FutureTask、RunnableFuture、Future、Runnable、Callable的关系

首先我们来看一下这几个类之间的关系依赖图:

现在开始分析源码,从FutureTask类开始,这个类由于实现了RunnableFuture接口,而该接口又继承了Runnable接口和Future接口,所以这个类实现的方法主要如下:run、cancel、isCancelled、isDone、get。前面一个是用来供线程调用,后面四个用来获取线程的执行结果。我们看看它的构造函数,主要有两个:

/**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Callable}.
     *
     * @param  callable the callable task
     * @throws NullPointerException if the callable is null
     */
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

    /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Runnable}, and arrange that {@code get} will return the
     * given result on successful completion.
     *
     * @param runnable the runnable task
     * @param result the result to return on successful completion. If
     * you don't need a particular result, consider using
     * constructions of the form:
     * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
     * @throws NullPointerException if the runnable is null
     */
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

从这两个构造函数可以看出,该类可以传入Callable和Runnable类实现的对象,但是不管传入的是哪个类实现对象,都最终会转换成Callable类实现对象,最终线程调用的函数是Callabe中的call函数,也就是说如果传入的是Runnable类实现对象,那么就会将该对象转换成Callable类实现对象,这个转换操作就是通过Executors.callable函数来实现的,我们进入到这个函数看看:

public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
 }

下面我们看看RunnableAdapter<T>的实现代码:

/**
     * A callable that runs given task and returns given result
     */
    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

这个类会将Runnable类实现对象和result存储到相应的类成员变量中,同时实现了一个call函数,这个函数中执行了Runnable类实现对象的run函数并返回result。流程图如下图所示:

最终如果传入的是Runnable实现类对象,也会转换成Callable。接下来我们来看看示例:

public class Test {
    public static void main(String[] args) {
        //第一种方式
        /*ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        executor.submit(futureTask);
        executor.shutdown();*/
         
        //第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        Thread thread = new Thread(futureTask);
        thread.start();
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("主线程在执行任务");
         
        try {
            System.out.println("task运行结果"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("所有任务执行完毕");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子线程在进行计算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}

执行结果如下:

子线程在进行计算
主线程在执行任务
task运行结果4950
所有任务执行完毕

猜你喜欢

转载自blog.csdn.net/weixin_39935887/article/details/81174012