Callable、Future与FutureTask

通常来说,我们使用RunnableThread来创建一个新的线程,但是它们是没有返回值的。而有时候我们希望开启一个线程去执行一个任务,并且这个任务执行完成后有一个返回值。

那么JDK提供了Callable接口与Future类为我们解决这个问题,这也是所谓的“异步”模型。

Callable接口

可以看到Callable是一个函数式接口。同时Callable是有返回值的,并且支持泛型。

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

那一般是怎么使用Callable的呢?Callable一般是配合线程池工具ExecutorService来使用的。这里举例介绍ExecutorService可以使用submit方法来让一个Callable接口执行。它会返回一个Future,我们后续的程序可以通过这个Future的get方法得到结果。

public class Task implements Callable {

    @Override
    public String call() throws Exception {
        return "call()方法";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Task task = new Task();
        Future<String> submit = executorService.submit(task);
        System.out.println(submit.get());
    }
}

输出结果:call()方法

Future接口

FutureCallable有着类似的地方,同样也是支持泛型和有返回结果。 Future接口只有几个比较简单的方法:

  • cancel()注意是试图取消,并不一定能取消成功。因为任务可能已完成、已取消、或者一些其它因素不能取消,存在取消失败的可能。boolean类型的返回值是“是否取消成功”的意思。参数paramBoolean表示是否采用中断的方式取消线程执行。

FutureTask类

FutureTask的几个状态:

  • 先看一下FutureTask

可以看到FutureTask是实现了RunnableFuture接口的。

  • 再看一下RunnableFuture接口

可以看到RunnableFuture接口同时继承了Runnable接口和Future接口

  • 那FutureTask类有什么用?为什么要有一个FutureTask类?前面说到了Future只是一个接口,而它里面的cancel,get,isDone等方法要自己实现起来都是非常复杂的。所以JDK提供了一个FutureTask类来供我们使用。

  • 修改一下上面的代码,改用FutureTask

使用上与第一个Demo有一点小的区别。首先,调用submit方法是没有返回值的。这里实际上是调用的submit(Runnable task)方法,而上面的Demo,调用的是submit(Callable task)方法。

然后,这里是使用FutureTask直接取get取值,而上面的Demo是通过submit方法返回的Future去取值。

最后更新于