0%

FutureTask 相关接口源码解析

本文重点分析 FutureTask 相关的所有接口和类,为后面 FutureTask 源码解析做个准备。

本文涉及到的接口:Callable / Runnable / Future / RunnableFuture
本文涉及到的类:Executors.RunnableAdapter

Runnable

Runnable 接口定义了一个无参无返回值的 run 方法。如果某个类的实例计划由一个线程来执行,则可以去实现 Runnable 接口。

Runnable 接口的设计,是为了给希望在活动状态执行代码逻辑的对象提供通用协议。例如,Thread 类实现了 Runnable。处于活动状态仅意味着线程已启动且尚未停止。

Runnable 接口提供了使类处于活动状态而不用作为 Thread 子类的方法。通过实例化 Thread 实例并将自身作为 target 传入,实现 Runnable 的类可以在不继承 Thread 的情况下运行(see Thread 源码解析-实现 Runnable 接口)。

大多数情况下,如果只需要重写 run() 方法而不是其他 Thread 方法,就应该使用 Runnable 接口。

Runnable

Callable

Callable 接口定义了一个无参有返回值的 call 方法。

Callable 接口类似于 Runnable 接口,因为两者都是为实例可以由另一个线程执行的类而设计。两者的区别是:Callable 可以返回任务的计算结果或任务运行时抛出的异常。

Callable

Future

Future 表示异步计算的结果。提供了 5 个管理任务的方法。只能在计算完成后通过 get 方法检索结果,该方法必要时会阻塞直到任务完成。

如果想使用 Future 但不提供可用结果,可以声明为 Future<?> 并返回 null 作为底层任务结果。

看下 Future 提供的 5 个方法:

cancel(boolean mayInterruptIfRunning);

mayInterruptIfRunning 参数决定在取消任务时是否应该中断执行此任务的线程来尝试停止该任务

cancel

isCancelled();

任务是否被取消。

isCancelled

isDone();

任务是否完成。

isDone

get()

等待计算完成,然后检索其结果。

get-1

get(long timeout, TimeUnit unit)

等待给定的计算完成时间,然后检索其结果(如果计算完成)。

get-2

RunnableFuture

RunnableFuture<V> extends Runnable, Future<V>

RunnableFuture 接口可以让 Future 对 Runnable 进行管理。

RunnableFuture

Executors.RunnableAdapter

RunnableAdapter<T> implements Callable<T>

典型的适配器模式,将 Runnable 适配为 Callable:RunnableAdapter 实现 Callable 接口,接着在 Callable 的 call 方法里面调用 Runnable 的 run 方法。

Executors.RunnableAdapter

boring question

Q1

为什么 RunnableFuture extends Runnable,但是 RunnableFuture 里还定义了一个 run() 方法?

真有人讨论这个问题:
https://stackoverflow.com/questions/25092787/why-does-java-util-concurrent-runnablefuture-have-a-run-method

大意是,从理论上来讲,确实没有什么必要(no technical significance),但是这么做,可以便于文档展示(specific JavaDoc to it)。

Q2

为什么 Runnable 里的 run() 方法是 public abstract 的?

也真有人讨论这个问题:
https://stackoverflow.com/questions/3289767/why-run-method-defined-with-abstract-keyword-in-runnable-interface

大意是,其实这种接口声明风格是不好的,这么做,也许是历史遗留,或者是作者的即兴创作。

其实这两个问题并没有标准答案,只是我看源码的时候突然想到的,就像生活,有趣且无聊。。


欢迎关注我的其它发布渠道