FutureTask源码解读
如有问题或者错误请及时留言联系作者
例如:源码解读错误/源码没解释清楚/自己没弄明白等等
前言
在 Java 1.5 我们创建线程的方式是继承Thread类或者实现Runnable接口,但是这两种方法都无法返回结果所以Doug Lea 在Jdk1.5引入了Callable接口以及FutureTask类来完成返回结果的获取,接下来就和我一起来探究FutureTask的原理吧
提示:以下是本篇文章正文内容,下面案例可供参考
一、FutureTask使用演示
FutureTask<String> futureTask = new FutureTask<>(() -> {
System.out.println("futureTask");
TimeUnit.SECONDS.sleep(10);
return "JJKING";
});
new Thread(futureTask).start();
System.out.println(futureTask.get());
返回结果:
我们可以看到引入了FutureTask我们就可以使用Callable接口来返回结果
二、构造方法
1.Runnable构造方法
public FutureTask(Runnable runnable, V result) {
//将runable接口转换为callable因为FutureTask里面存储的是Callable变量
this.callable = Executors.callable(runnable, result);
//设置任务运行状态为未运行态
this.state = NEW;
}
public static <T> Callable<T> callable(Runnable task, T result) {
//对任务进行判空操作
if (task == null)
throw new NullPointerException();
//使用适配器设计模式把Runnable适配成Callable
return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
//保存的Runnable接口
final Runnable task;
//保存的返回值
final T result;
//如何适配的就是适配器RunableAdapter实现Callable接口并且把
//Runnable 和结果设计成成员变量保存起来
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
//调用的时候直接调用的Runnable的run方法运行
public T call() {
task.run();
return result;
}
}
2.Callable构造方法
public FutureTask(Callable<V> callable) {
//对传入的Callable实例机型判空
if (callable == null)
throw new NullPointerException();
//给成员变量callable赋值为传过来的参数
this.callable = callable;
//设置任务运行状态为未运行状态
this.state = NEW;
}
2.变量解读
//当前任务的状态使用state变量来表示(使用了volatile来保证多线程下的可见性)
private volatile int state;
//New:当前任务还未执行
private static final int NEW = 0;
//COMPLETING:当前任务即将完成但是还没有完成
private static final int COMPLETING = 1;
//NORMAL:当前任务正常结束
private static final int NORMAL = 2;
//EXCEPTIONA:当前任务异常结束
private static final int EXCEPTIONAL = 3;
//CANCELLED:当前任务已被取消
private static final int CANCELLED = 4;
//INTERRUPTING:当前任务正处于中断中
private static final int INTERRUPTING = 5;
//INTERRUPTED:当前任务已被中断
private static final int INTERRUPTED = 6;
//实现任务的Callable接口使用callable变量来保存
private Callable<V> callable;
//接收结果的对象(使用Object类型注意有可能结果有异常)
//todo: 问题1:为什么outcome不需要volatile修饰
private Object outcome;
//当前执行任务的线程
private volatile Thread runner;
/**
* waiters(由于有多个线程可能get所以使用WaitNode来存储多个线程)
*/
private volatile WaitNode waiters;
//unsafe对象的获取
private static final sun.misc.Unsafe UNSAFE;
//获取状态内存偏移量
private static final long stateOffset;
//获取执行任务的内存偏移量
private static final long runnerOffset;
//等待队列头的内存偏移量
private static final long waitersOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = FutureTask.class;
stateOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("state"));
runnerOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("runner"));
waitersOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("waiters"));
} catch (Exception e) {
throw new Error(e);
}
}
3.代码debug演示
FutureTask<String> futureTask = new FutureTask<>(() -> {
System.out.println("futureTask");
TimeUnit.SECONDS.sleep(10);
return "JJKING";
});
System.out.println(futureTask.get());
总结
提示:这里对文章进行总结: