FutureTask源码解析一
FutureTask源码解析一
https://blog.csdn.net/jiangtianjiao/article/details/104029225
考虑到文章篇幅过长,分为两篇讲解
本片主要介绍FutureTask涉及的一些接口和基本知识
FutureTask简介
FutureTask是一种可取消的异步计算任务,它实现了Future接口,代表了异步任务的返回结果。从而FutureTask可以启动和取消异步计算任务、查询异步计算任务是否完成和获取异步计算任务的返回结果。只有异步计算任务结束时才能获取返回结果,当异步计算任务还未结束时调用get方法会使线程阻塞。一旦异步计算任务完成,计算任务不能重新启动或者取消,除非调用runAndReset。
FutureTask继承关系图
image-20210311194746175.pngFutureTask实现了RunnableFuture,RunnableFuture结合了Future和Runnable。
下面对上述接口进行逐个分析
①Runnable接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
run方法定义了线程要执行的任务,但无返回值,那么需要返回值又该怎么办? 引入callable接口,callable能返回任务的执行结果。
②Callable接口
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
相对于Runable,Callable具有返回值,可以向上抛出异常,而Runnable的run方法不能抛出异常,只能在方法内部进行catch处理。
③Future接口
Future接口用来代表一个异步操作的执行结果。我们可以用它来获取一个操作的执行结果、取消一个操作、判断一个操作是否已经完成或者是否被取消。
public interface Future<V> {
// 该方法用来获取执行结果, 如果任务还在执行中, 就阻塞等待
V get() throws InterruptedException, ExecutionException;
// 该方法同get方法类似, 不同的是它最多等待指定的时间, 如果指定时间内任务没有完成, 则会抛出TimeoutException异常;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
// 该方法用来尝试取消一个任务的执行, 它的返回值是boolean类型, 表示取消操作是否成功.
boolean cancel(boolean mayInterruptIfRunning);
// 该方法用于判断任务是否被取消了。如果一个任务在正常执行完成之前被cancel掉了, 则返回true
boolean isCancelled();
// 如果一个任务已经结束, 则返回true
// 任务结束包含了以下三种情况,见下面3)
boolean isDone();
}
根据FutureTask.run()方法被执行的时机,FutureTask可以处于下面3种状态
- ①未启动
FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态。
当创建一个FutureTask且没有执行FutureTask.run()方法之前,这个FutureTask处于未启动状态。 - ②已启动
FutureTask.run()方法被执行的过程中,FutureTask处于已启动状态。 - ③已完成
FutureTask.run()方法执行完后正常结束或被取消FutureTask.cancel(…),或执行FutureTask.run()方法时抛出异常而结束,FutureTask处于已完成状态。
当FutureTask处于未启动或已启动状态时,执行FutureTask.get()方法将导致调用线程阻塞。
当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或抛出异常。
当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会被执行。
当FutureTask处于已启动状态时,执行FutureTask.cancel(true)方法将以中断执行此任务线程的方式来试图停止任务。
注意:线程中断仅仅是置线程的中断状态位,并不会停止线程,需要用户自己去监视线程的状态为并做进一步处理。
当FutureTask处于已启动状态时,执行FutureTask.cancel(false)方法将不会对正在执行此任务的线程产生影响。
注意:此时会让正在执行的任务运行完成。
当FutureTask处于已完成状态时,执行FutureTask.cancel(...)方法将返回false。
④RunnableFuture 接口
RunnableFuture接口同时继承了Runable与Callable接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
FutureTask涉及工具类
①Executors
Executors是一个用于创建线程池的工厂类,同时提供了一些有用的静态方法,比如FutureTask中使用到的接口Executors.callable(runnable, result),此处该类不是重点,不作过多解析,只简单描述与FutureTask相关部分。
public class Executors {
/**
* Returns a {@link Callable} object that, when
* called, runs the given task and returns the given result. This
* can be useful when applying methods requiring a
* {@code Callable} to an otherwise resultless action.
* @param task the task to run
* @param result the result to return
* @param <T> the type of the result
* @return a callable object
* @throws NullPointerException if task null
*/
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
/**
* 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;
}
}
// RunnableAdapter采用了适配器模式,将一个Runnable类型对象适配成Callable类型。
// 对于result原样返回并无什么意义,只是适配成Callable需要返回值。
}
②Unsafe
Unsafe 是 sun.misc 包下的一个类,可以直接操作堆外内存,可以随意查看及修改JVM中运行时的数据,使Java语言拥有了类似C语言指针一样操作内存空间的能力。Unsafe 的操作粒度不是类,而是内存地址和所对应的数据,增强了Java语言操作底层资源的能力。后面单独写一篇关于Unsafe使用的文章,此处不是重点,不做解析。