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).今天我们通过一个小的案例 ...
随机推荐
- Android控件——ImageView
android:orientation="vertical" 修改布局文件垂直排列 放置图片: 1.通过src引入图片: 2.通过background引入背景图片 3.baco ...
- visual studio 个性化设置
尼马visual studio 的注释建设的真垃圾 Ctrl+K+C Ctrl+K+U, 通过工具->选项->环境->键盘->命令包含中搜索“注释选定内容”,分配成 Ctrl+ ...
- 【UOJ224】短路
具体可以看UOJmyy的blog,orz 就是一个贪心. #include<bits/stdc++.h> typedef long long ll; using namespace std ...
- xcode 配置系统环境变量 Preporocessing 预编译宏的另一种写法, 系统的DEBUG 由来
在某些项目中看到一些环境变量类似宏的东西 比如叫ENVIRONMENT, 但发现还找不到具体这个宏是什么值, 那是因为他实在Preprocessing里配置了这个宏的值, 他能配置debug/rele ...
- Nginx-1.6.3反向代理
源码安装nginx cat /etc/redhat-release uname -rm yum install pcre-devel openssl-devel -y rpm -qa pcre pcr ...
- LeetCode解题报告—— Maximal Rectangle
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and ...
- QT中ui更改后不能更新的解决方法
ui源文件到界面显示的原理可以网上搜索,这里不再描述.简单讲就是先要从*.ui生成ui_*.h然后再编译,所以界面未更新实际上是因为ui_*.h这个文件没有更新导致的. 出现此问题后我尝试了以下几个方 ...
- Linux系统格式化磁盘+挂载分区
1.查看可使用的磁盘: $fdisk -l 2.对磁盘进行分区: $fdisk /dev/vdb 3.格式化磁盘: $fdisk -l --查看已经分区的磁盘 $mkfs -t ext4 /dev/v ...
- AC日记——Sagheer and Nubian Market codeforces 812c
C - Sagheer and Nubian Market 思路: 二分: 代码: #include <bits/stdc++.h> using namespace std; #defin ...
- cordova plugin 大全及安装命令
前言:用cordova开发hybrid app的过程中,由于是html5开发的app,在手机上很多权限受限制,这就导致了我们需要安装很多插件来弥补这一缺点.在网上搜了好久,感觉都不是很全,所以自己整理 ...