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).今天我们通过一个小的案例 ...
随机推荐
- fork与printf缓冲问题
printf输出条件: (1) 调用fflush: (2) 缓冲区满了: (3) 遇到\n \r这些字符 (4) 遇到scanf这些要取缓冲区的: (5) 线程或者进程退出: fork之后会拷贝父进程 ...
- Linux 入门记录:十三、Linux 扩展权限
一.默认权限 每一个终端都有一个 umask 属性,是用来确定新建文件或目录的默认权限的“掩码”(mask 有“掩码”的含义,至于 u,后面说). Linux 中一般有默认的权限掩码,使用命令 uma ...
- 【jzoj2017.8.21提高组A】
太菜了,刷刷NOIP题玩玩. 今天的题好像以前有做过(雾) A. #include<bits/stdc++.h> typedef long long ll; ],cnt; ll x; in ...
- mongodb循环
var rds = db.REGIPATIENTREC.find({mzh:{$lt:"0"},usrOrg:"石景山中西医结合医院"}); var show ...
- service XXX start启动报start: Rejected send message, 1 matche
转,原文地址:http://blog.sina.com.cn/s/blog_56d8ea9001018w1l.html [问题]start: Rejected send messag现象:crifan ...
- SPOJ Two Paths
Description 给定一个无向图,含有一定的路.从中找出两个最长的路径(每条路径有一些相通路组成)这两个路径不能经过公共的点,求何时二路径的乘积最大. 本题给出的无向图是一棵树,每边权值为1. ...
- telent
telnet ip 空格 port ctrl+] 进入 命令后 quit 退出 在linux/unix下使用telnet hostname port连接上主机后会提示Escape chara ...
- python语言的模块化
在实际工程中使用的编程语言,都有(也应该有)自己的模块化方式,这是由于:一个文件不可能写的无限长,把不同性质和功能的代码放入不同的文件,再由文件组成不同的文件夹,这种方式符合人们思考和理解的习惯,不过 ...
- JS框架的实现
众多流行的JS库都不同程度的污染了原生JS,最典型的如Prototype ,Mootools .JQuery则完全例外,一个匿名函数执行后便诞生了集所有API为一身的强大 $ .虽然如此,JQuery ...
- JSON字符串转对象
JSON(JavaScript Object Notation) JavaScript对象标记法:JSON是与JavaScript高度契合的:JSON 语法: --数组(Array)用" ...