@SuppressWarnings({"unchecked","restriction"})
public class FutureTask1<V> implements RunnableFuture<V> { /*
任务可能出现的状态转换
NEW新建 -> COMPLETING即将完成 -> NORMAL正常结束
NEW新建 -> COMPLETING即将完成 -> EXCEPTIONAL异常
NEW新建 -> CANCELLED被取消
NEW新建 -> INTERRUPTING即将被中断 -> INTERRUPTED已经被中断 第一种:初始化状态:NEW新建
第二种:中间状态:COMPLETING即将完成,INTERRUPTING即将被中断
第三种:终端状态:NORMAL正常结束,EXCEPTIONAL异常,CANCELLED被取消,INTERRUPTED已经被中断
*/
private volatile int state;//任务当前状态,任务的状态可能被其他线程修改,所以要CAS。
private static final int NEW = ;//新建
private static final int COMPLETING = ;//即将完成。get(),finishCompletion(),awaitDone()使用这个状态。
private static final int NORMAL = ;//正常结束,返回结果值。report()使用这个变量。
private static final int EXCEPTIONAL = ;//异常,不返回结果值,抛出异常。没有使用这个状态。
private static final int CANCELLED = ;//被取消,不返回结果值,抛出异常。report(),isCanceld()方法使用这个变量。
private static final int INTERRUPTING = ;//即将被中断,不返回结果值,抛出异常。run()方法最后会使用这个状态。
private static final int INTERRUPTED = ;//已经被中断,不返回结果值,抛出异常。没有使用这个状态。 //FutureTask里面只能是callable,即使传进来Runnable也会转换为callable,
//也就是FutureTask真正执行的任务。Thread里面只能丢Runnable,要想FutureTask丢到线程池里面去,也必须是Runnable。
//finishCompletion()置为null
private Callable<V> callable;
private Object outcome;//get()返回的结果
private volatile Thread runner;//执行callable任务的线程,它是CAS操作。run()的最后finally置为null。
private volatile WaitNode waiters;//等待结果的线程集合 //根据状态s决定是否返回结果
private V report(int s) throws ExecutionException {
Object x = outcome;//我们在set()方法的时候把结果写进outcome的
if (s == NORMAL)//只有是正常才返回结果。其余
return (V) x;
if (s >= CANCELLED)//CANCELLED4被取消,INTERRUPTING5即将被中断,INTERRUPTED6已经被中断,
throw new CancellationException();
throw new ExecutionException((Throwable) x);
} //把Callable封装为FutureTask1
public FutureTask1(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
} //把Runnable封装为FutureTask1,result是预期值。
public FutureTask1(Runnable runnable, V result) {
this.callable = Executors1.callable(runnable, result);//runnbale封装为callable
this.state = NEW;
} //判断是否取消了,包括cancel(false);和cancel(true);
public boolean isCancelled() {
return state >= CANCELLED;//CANCELLED被取消,INTERRUPTING即将被中断,INTERRUPTED已经被中断
} //任务是否结束,不一定是成功任务,取消了,出异常了,被中断了,也是结束,包括cancel(false);和cancel(true);run(),setException(),set(),
public boolean isDone() {
return state != NEW;
} //取消任务。如果是false NEW0->CANCELLED4 true: NEW ->INTERRUPTING5->中断线程->INTERRUPTED6
public boolean cancel(boolean mayInterruptIfRunning) {
//fasle&&:处于不是新建状态:返回fasle,状态不变。
//true&&false:处于新建状态,但是状态设置失败:返回fasle,状态不变。
if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))//即将被中断5,被取消4
return false;
//true&&true:是新建状态,并且 状态设置成功(将其置为INTERRUPTING5或者CANCELLED4):继续状态变为INTERRUPTED6
try {
if (mayInterruptIfRunning) {//true才继续变为INTERRUPTED
try {
Thread t = runner;
if (t != null)
t.interrupt();//使用了线程中断的方法来达到取消任务的目的,设置中断标记=true
} finally { // final 已经被中断6
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);//
}
}
} finally {
finishCompletion();
}
return true;
} //获取执行结果,阻塞,获得Callable的返回值
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)//COMPLETING1即将完成,NEW新建,如果任务还没执行完成,就等待任务先执行完成
s = awaitDone(false, 0L);
//s > COMPLETING:正常结束,异常,被取消,即将被中断,已经被中断
return report(s);
} //获取任务执行的结果,并且有超时机制
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
//带有超时时间的get(),如果超过指定时间,就会抛出一个TimeoutException
if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
} protected void done() {
} protected void set(V v) {//先设置即将完成,再设置正常结束
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {//即将完成1
outcome = v;//把任务执行的结果写入到outcome当中,
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); //final 正常结束2
finishCompletion();//唤醒等待结果的线程
}
} //修改当前任务的状态
protected void setException(Throwable t) {//先设置即将完成,再设置异常
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {//即将完成1
outcome = t;//把任务执行的结果写入到outcome当中,
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final 异常3
finishCompletion();//唤醒等待结果的线程
}
} //任务起动就调这个方法。
public void run() {
//true||:不是新建,已经执行了,就不执行
//fasle||true:是新建,runner设置当前线程失败了,就不执行
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))//不能多线程进来
return;
//false||fasle:是新建,设置runner成功就进去
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();//Callable的call方法,如果是Runnable封装的Callable,call方法返回的是RunnableAdapter的期望值。
ran = true;
} catch (Throwable ex) {//call()抛出了异常
result = null;
ran = false;
setException(ex);//状态不是NEW就不设置异常结果。先设置即将完成,再设置异常。设置1 3
}
if (ran)
set(result);//设置结果,状态不是NEW就不设置结果。先设置即将完成,再设置正常结束。设置1 2。
}
} finally {
//在任务执行的过程中,可能会调用cancel(),这里主要是不想让中断操作逃逸到run()方法之外
runner = null;//可以多线程进来了
int s = state;
if (s >= INTERRUPTING)//即将被中断5和已经被中断6。调用了cancel(true)现在s=5|6。调用cancel(false)=4不会进来。
handlePossibleCancellationInterrupt(s);
}
} protected boolean runAndReset() {
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable<V> c = callable;
if (c != null && s == NEW) {
try {
c.call(); // don't set result
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} finally {
//在任务执行的过程中,可能会调用cancel(),这里主要是不想让中断操作逃逸到run()方法之外
runner = null;
s = state;
if (s >= INTERRUPTING)//INTERRUPTING5即将被中断,INTERRUPTED6已经被中断。调用了cancel(true)。
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
} private void handlePossibleCancellationInterrupt(int s) {
if (s == INTERRUPTING)//5,如果cancel(true)并且现在是5
while (state == INTERRUPTING)
Thread.yield(); // 避免过多的CPU时间放在这个for循环的自旋上,让步等着变为INTERRUPTED6,等着runner线程被设置中断标记在退出,就是在收集cancel(true)的中断标记再出去。 // assert state == INTERRUPTED;
// 清除cancel(true)的中断,中断是任务task和调用者通信的机制,
// Thread.interrupted(); //重置中断状态为未中断=false; isInterrupted不会重置中断状态;
} static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;//下一个 WaitNode() {
thread = Thread.currentThread();
}
} //成功|取消 完成任务后唤醒等待结果的线程。cancel()设置s=4|6后调用这个方法,run()正常完成设置s=2,run()异常完成设置s=3后调用这个方法。
//awaitDone()唤醒的线程走if(s > COMPLETING1)返回状态值去get()获取结果。

private void finishCompletion() {
assert state > COMPLETING;//正常结束,异常,被取消,即将被中断,已经被中断
for (WaitNode q; (q = waiters) != null;) {//从头开始唤醒 //设置为null之后,其他get线程看到状态>1,直接获取结果,不加入waiters队列。
//如果其他线程成功加入到了另一个新的waiters队列,此时唤醒失败,就要另一个线程他自己去退出。
//这里准备开始清空等待队列了,就要阻止其他线程进到队列来(通过状态值),如果清空后还是进到队列去了,就要线程自己处理。

if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;//thread属性置为null
LockSupport.unpark(t);//唤醒的是获取结果的awaitDone()阻塞的线程
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; //gc q,q.next不会回收,因为还有next指向在。
System.gc();
System.gc();
System.gc();
System.gc();
System.gc();
q = next;
}
break;
}
}
//一个钩子方法,本类中,它是一个空实现,在子类中可以重写它。
done();
//最后把callable置为null.
callable = null; // to reduce footprint
} //等待任务完成,多线程进来,唤醒之后,返回状态去get获取结果。2个出口。
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;//超时时间,如果使用了超时的get()才起作用,否则这个值不起作用
WaitNode q = null;
boolean queued = false;
for (;;) {
if (Thread.interrupted()) {//等待结果的线程被中断了
removeWaiter(q);//移除无效节点
throw new InterruptedException();//就抛出一个中断异常
} /*分为几部操作:每一步都在一个for循环里面,只有前面一步执行了才能在下一个循环里面执行下一步*/ int s = state; //如果当前状态大于COMPLETING,说明任务已经正常完成了或者取消完成了。就去拿结果。拿到的结果可能是null就抛出异常。
//NORMAL正常结束,EXCEPTIONAL异常,CANCELLED被取消,INTERRUPTING即将被中断,INTERRUPTED已经被中断
if (s > COMPLETING) {
if (q != null)
q.thread = null;//回收q.thread
return s;//返回任务的状态,等待结束。有可能是cancel()设置s=4|6后唤醒,有可能是run()设置s=2后唤醒,run()设置s=3后唤醒。 // 正在完成,先等一会,下次循环去初始化节点--压栈--阻塞
} else if (s == COMPLETING)
Thread.yield();//避免过多的CPU时间放在这个for循环的自旋上。再次判断状态。 else if (q == null)//初始化q节点,才能去压栈,才能去阻塞。(后面2步在下一个循环中处理,会跳过这个循环)
q = new WaitNode();//再次判断状态。 else if (!queued)//将q节点压入栈,它是一个cas操作。第一次是false,压栈成功变为true,再去阻塞。也就是说只有压栈了才能去阻塞。后来的在前面。
//有可能唤醒不了:finishCompletion()已经执行完了,才加入到队列就不能唤醒,就加入到一个新的waiters里面去了,就要再次循环,通过状态退出。
queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
//再次判断状态。
else if (timed) {//如果有超时限制的话,判断是否超时,如果没有超时就重试,如果超时了,就把q节点从栈中遇除
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {//超时了
removeWaiter(q);//移除无效节点,多线程进来
return state;//返回状态,去获取结果。
}
LockSupport.parkNanos(this, nanos);//LockSupport是一个并发工具,这里表示等待nanos秒后唤醒
} else
LockSupport.park(this);//开始阻塞线程,直到任务完成了才会再次唤醒了在finishCompletion()中唤醒
}
} /*
将某个节点置为无效节点,并清除栈中所有的无效节点
(通过前面的分析,应该可以推断出,无效的节点,其实就是指节点内部的thread == null)
那么产生无效节点的情况就有三种了
(1):线程被中断了
(2):s > COMPLETING,当前的任务状态> COMPLETING
(3):超时
*/
//如果在阻塞其间,任务被中断了,或者超时了,又或者任务已经完成了,都需要进行资源的回收。
private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;//为了GC回收node节点中的thread成员变量
retry:
for (;;) {//从头到尾删除thread=null的。不仅仅删除node。 /* 多线程不会有影响,其他线程只是做了重复的事情,或者可以帮着其他线程做 */ for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;//q不为null,pred只要被赋值了就不为null。
else if (pred != null) {
pred.next = s;
if (pred.thread == null)
continue retry;//如果前驱节点也是一个无效节点,则重新遍历, //q.thread异常了,pred=null,说明pred没有被赋值过,第一个q就异常了。
} else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s))//修改头结点是多线程在修改。修改失败就重来。
continue retry;//调到外层循环再来。
}
break;
}
}
} private static final sun.misc.Unsafe UNSAFE;
private static final long stateOffset;//state
private static final long runnerOffset;//runner
private static final long waitersOffset;//waiters
static {
try {
UNSAFE = java.security.AccessController
.doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
for (java.lang.reflect.Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x))
return k.cast(x);
}
throw new NoSuchFieldError("the Unsafe");
}
});
Class<?> k = FutureTask1.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源码2的更多相关文章

  1. Java 多线程(五)—— 线程池基础 之 FutureTask源码解析

    FutureTask是一个支持取消行为的异步任务执行器.该类实现了Future接口的方法. 如: 取消任务执行 查询任务是否执行完成 获取任务执行结果(”get“任务必须得执行完成才能获取结果,否则会 ...

  2. FutureTask 源码分析

    FutureTask 源码分析,这个类的原理与我分析android当中的FutureTask类差不多[http://www.cnblogs.com/daxin/p/3802392.html] publ ...

  3. FutureTask 源码解析

    FutureTask 源码解析 版权声明:本文为本作者原创文章,转载请注明出处.感谢 码梦为生| 刘锟洋 的投稿 站在使用者的角度,future是一个经常在多线程环境下使用的Runnable,使用它的 ...

  4. Java多线程类FutureTask源码阅读以及浅析

    FutureTask是一个具体的实现类,实现了RunnableFuture接口,RunnableFuture分别继承了Runnable和Future接口,因此FutureTask类既可以被线程执行,又 ...

  5. FutureTask源码深度剖析

    FutureTask源码深度剖析 前言 在前面的文章自己动手写FutureTask当中我们已经仔细分析了FutureTask给我们提供的功能,并且深入分析了我们该如何实现它的功能,并且给出了使用Ree ...

  6. Java并发编程笔记之FutureTask源码分析

    FutureTask可用于异步获取执行结果或取消执行任务的场景.通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过Fu ...

  7. FutureTask源码解析

    在Java中一般通过继承Thread类或者实现Runnable接口这两种方式来创建多线程,但是这两种方式都有个缺陷,就是不能在执行完成后获取执行的结果,因此Java 1.5之后提供了Callable和 ...

  8. 并发编程—— FutureTask 源码分析

    1. 前言 当我们在 Java 中使用异步编程的时候,大部分时候,我们都会使用 Future,并且使用线程池的 submit 方法提交一个 Callable 对象.然后调用 Future 的 get ...

  9. Java Future 和 FutureTask 源码Demo

    Future 是一个接口,看源码有Future 和 FutreTask 使用Demo package java.util.concurrent; /** * A <tt>Future< ...

  10. FutureTask源码阅读

    FutureTask功能用法 类结构 源码中详细说明了FutureTask生命周期状态及变化 /** * The run state of this task, initially NEW. The ...

随机推荐

  1. c# 模拟表单提交,post form 上传文件、数据内容

    转自:https://www.cnblogs.com/DoNetCShap/p/10696277.html 表单提交协议规定:要先将 HTTP 要求的 Content-Type 设为 multipar ...

  2. Java编程基础——数组和二维数组

    Java编程基础——数组和二维数组 摘要:本文主要对数组和二维数组进行简要介绍. 数组 定义 数组可以理解成保存一组数的容器,而变量可以理解为保存一个数的容器. 数组是一种引用类型,用于保存一组相同类 ...

  3. 原生js与jquery加载页面元素比较

    原生js:将获取元素的语句写到页面头部,会因为元素还没有加载而出错,js提供了window.onload 这个方法事先加载元素 <script type="text/javascrip ...

  4. PHP开发之--安装composer

    composer是一个很好用的工具,类似于iOS开发项目中所用的cocopods,所以就想着安装下,过程也很简单: 1.切换到如下目录(在很多博客中都是这样写的,先安装,然后mv到/usr/local ...

  5. Windows出现“引用账户被锁定,且暂时无法登录”解决方法

    1. 问题描述如下: i. 远程桌面登录时,出现提示必须修改密码才能登录,是因为密码过期所导致的,如下图: ii. 当我们登录Windows控制台(基于OpenStack平台的虚拟机)进行修改密码时, ...

  6. mysql数据库之忘记root密码

    1.  vi /etc/my.cnf,在[mysqld]中添加 skip-grant-tables 例如: [mysqld] skip-grant-tables datadir=/var/lib/my ...

  7. oracle_day1

    本节内容: 1:oracle的服务 2:oracle 11 G 的新功能 3:数据库的三大范式 1:oracle的服务 安装完oracle 想要使用oracle 必须要启动的两个服务. 要是还想要使用 ...

  8. destoon漏洞修复关于 $do->add($post); SQL注入修改

    在阿里云漏洞提示查看发现destoon有关于mobile/guestbook.php $do->add($post); SQL注入修改 漏洞名称:Destoon SQL注入 补丁文件:/mobi ...

  9. TensorFlow语法点滴

    1. tf.variable_scope生成一个上下文管理器,用于获取已经生成的变量 with tf.variable_scope('pnet'): data = tf.placeholder(tf. ...

  10. mysql select limit 大数据量查询 性能终极提升方法

    还是广告位 我们的使用mysql的时候总是想当然的使用 select × from tables where a>0 order by id desc limit 500000,200 当我们真 ...