FutureTask源码分析
1. 常量和变量
private volatile int state; // 任务状态
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
// run正常执行:NEW -> COMPLETING -> NORMAL
// run异常执行:NEW -> COMPLETING -> EXCEPTIONAL
// cancel(false):NEW -> CANCELLED
// cancel(true):NEW -> INTERRUPTING -> INTERRUPTED private Callable<V> callable; // 任务
private Object outcome; // 执行结果
private volatile Thread runner; // 任务执行线程(在run方法中置为当前线程)
private volatile WaitNode waiters; // 任务等待链表(头节点)
2. 构造方法
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
} public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result); // RunnableAdapter implements Callable
this.state = NEW;
}
3. 等待节点
static final class WaitNode {
volatile Thread thread; // 等待线程
volatile WaitNode next; // 下一等待节点
WaitNode() { thread = Thread.currentThread(); }
}
4. 实现Future接口
1)cancel
public boolean cancel(boolean mayInterruptIfRunning) {
// 任务状态为NEW && CAS设置state = INTERRUPTING || CANCELLED
if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try {
if (mayInterruptIfRunning) { // 允许在任务执行时被中断
try {
Thread t = runner;
if (t != null) // 任务尚未执行完毕
t.interrupt(); // 中断任务所在线程
} finally {
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // state = INTERRUPTED
}
}
} finally {
finishCompletion(); // 唤醒所有等待任务执行结果的线程(见get和awaitDone方法)
}
return true;
} private void finishCompletion() {
for (WaitNode q; (q = waiters) != null;) { // 从头节点(q)开始遍历waiters链表
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { // CAS设置waiters链表为空
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null; // 标记节点q被唤醒
LockSupport.unpark(t); // 唤醒线程
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null;
q = next;
}
break;
}
}
done(); // noop
callable = null;
} protected void done() { }
2)isCancelled和isDone
public boolean isCancelled() { // 任务是否已取消执行
return state >= CANCELLED;
} public boolean isDone() { // 任务是否执行完毕(对外如此,对内是 <= COMPLETING)
// cancel方法直接设置任务状态为INTERRUPTING || CANCELLED,run方法中在set执行结果时设置任务状态为COMPLETING
return state != NEW;
}
3)get
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L); // 永久等待
return report(s);
} public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
// 在timeout时间内等待
if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
} private int awaitDone(boolean timed, long nanos) throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L; // 计算截止时间
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) { // 检查清除中断,移除等待节点,抛出异常
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) { // 任务执行完毕
if (q != null) // 已建立任务等待节点
q.thread = null;
return s;
}
else if (s == COMPLETING) // 任务执行中
Thread.yield();
else if (q == null) // 任务尚未执行(s == NEW),则建立任务等待节点q
q = new WaitNode();
else if (!queued) // q尚未排队,则CAS设置q为头节点
queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
else if (timed) { // 定时等待
nanos = deadline - System.nanoTime();
if (nanos <= 0L) { // 超时,则移除所有已被唤醒的节点
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos); // 在naos时间内等待
}
else
LockSupport.park(this); // 永久等待
}
} private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;
retry:
for (;;) {
// pred被唤醒 || CAS(waiters)失败:回到此处
for (WaitNode pred = null, q = waiters, s; q != null; q = s) { // 从头节点(q)开始遍历waiters链表
s = q.next;
if (q.thread != null) // q未被唤醒
pred = q;
else if (pred != null) { // q已被唤醒 && q前存在未被唤醒节点
pred.next = s; // 在链表中删除p
if (pred.thread == null) // pred被唤醒(其它线程正在同步finishCompletion:cancel || run) || pred超时(其它线程正在同步removeWaiter)
continue retry;
}
// q已被唤醒 && q前不存在未被唤醒节点,则CAS设置头节点为q.next
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s))
continue retry;
}
break;
}
}
}
5. 实现Runnable接口
public void run() {
// 任务未开始执行 || CAS设置runner = Thread.currentThread失败
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true; // 执行成功
} catch (Throwable ex) {
result = null;
ran = false; // 执行失败
setException(ex); // 设置异常的执行结果
}
if (ran)
set(result); // 设置正常的执行结果
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s); // 任务可能正在被其它线程cancel:等待cancel的完成
}
} protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { // CAS设置state = COMPLETING(任务可能已被cancel)
// CAS(state)成功
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // state = NORMAL
finishCompletion(); // 唤醒所有任务等待节点
}
} protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { // CAS设置state = COMPLETING(任务可能已被cancel)
// CAS(state)成功
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // state = EXCEPTIONAL
finishCompletion(); // 唤醒所有任务等待节点
}
} private void handlePossibleCancellationInterrupt(int s) {
if (s == INTERRUPTING)
while (state == INTERRUPTING)
Thread.yield();
}
6. 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);
}
}
FutureTask源码分析的更多相关文章
- FutureTask 源码分析
FutureTask 源码分析,这个类的原理与我分析android当中的FutureTask类差不多[http://www.cnblogs.com/daxin/p/3802392.html] publ ...
- Java并发编程笔记之FutureTask源码分析
FutureTask可用于异步获取执行结果或取消执行任务的场景.通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过Fu ...
- 并发编程—— FutureTask 源码分析
1. 前言 当我们在 Java 中使用异步编程的时候,大部分时候,我们都会使用 Future,并且使用线程池的 submit 方法提交一个 Callable 对象.然后调用 Future 的 get ...
- FutureTask源码分析(JDK7)
总览 A cancellable asynchronous computation. This class provides a base implementation of {@link Futur ...
- JUC源码分析-线程池篇(二)FutureTask
JUC源码分析-线程池篇(二)FutureTask JDK5 之后提供了 Callable 和 Future 接口,通过它们就可以在任务执行完毕之后得到任务的执行结果.本文从源代码角度分析下具体的实现 ...
- Java 多线程(五)—— 线程池基础 之 FutureTask源码解析
FutureTask是一个支持取消行为的异步任务执行器.该类实现了Future接口的方法. 如: 取消任务执行 查询任务是否执行完成 获取任务执行结果(”get“任务必须得执行完成才能获取结果,否则会 ...
- Java异步编程——深入源码分析FutureTask
Java的异步编程是一项非常常用的多线程技术. 之前通过源码详细分析了ThreadPoolExecutor<你真的懂ThreadPoolExecutor线程池技术吗?看了源码你会有全新的认识&g ...
- 线程之Callable、Future 和FutureTask使用及源码分析
一.Callable 我们知道启动线程有以下两种方式(jdk源码注释中官方定义只有两种启动方式,callable不算线程启动方式) 原文链接:http://www.studyshare.cn/blog ...
- android高级---->AsyncTask的源码分析
在Android中实现异步任务机制有两种方式,Handler和AsyncTask,它在子线程更新UI的例子可以参见我的博客(android基础---->子线程更新UI).今天我们通过一个小的案例 ...
随机推荐
- import学习
一.import as import socket, os, regex模块导入时可以使用 as 关键字来改变模块的引用对象名字: import os as system //当多个引入时 ...
- 【转】使用SQL语句创建和删除约束
转自http://blog.csdn.net/hamber_bao/article/details/6504905 约束的目的就是确保表中的数据的完整性. 常用的约束类型如下: 主键约束:(Prima ...
- c语言中的size_t
size_t unsigned int 类型,无符号,它的取值没有负数.用来表示 参数/数组元素个数,sizeof 返回值,或 str相关函数返回的 size 或 长度.sizeof 操作符的结果类型 ...
- IBM InfoSphere DataStage and QualityStage
Info coms from https://www.ibm.com/support/knowledgecenter/en/SSZJPZ_9.1.0/com.ibm.swg.im.iis.ds.nav ...
- Perl6 Bailador框架(2):路径设置
use v6; use Bailador; =begin pod get表示是get发送 post表示是post发送 get/post 后面的 '/name' 表示是路径 => sub {} 是 ...
- linux指令和文件系统
linux root用户的主目录是 /root , 其余用户在 /home 中: tar 常用 tar -zxvf : 安装使用 yum or wget website: mv a.g b.g 重命名 ...
- git - 使用原理
对git操作最大的功臣就是.git目录下的HEAD HEAD是什么 HEAD其实是一个类似于指针的东西,只不过这个指针的含义是指向当前的分支,当你再[ git checkout 分支 ] 的时候这个分 ...
- C++ STL结构总结
1. 什么是STL 它的全名是stand template library, 标准模板库,主要是将一些结构和算法写成模板,以便能够实现对任意类型的对象都可以操作,而不需要再一次去写一些算法及结构. 它 ...
- 分割线用CSS样式做出来的效果
一:单个标签实现分隔线:. ; ; line-height: 1px; border-left: 200px solid #ddd; border-right: 200px solid #ddd; t ...
- linux命令(30):touch命令
实例一:创建不存在的文件 touch test.log test1.log 实例二:更新log.log的时间和log2012.log时间戳相同 touch -r test.log test1.log ...