FutureTask阅读笔记


文章目录

  • FutureTask阅读笔记
  • 一、简介
  • 二、继承关系图
  • 三、存储结构
  • 四、源码分析
  • 内部类
  • 属性
  • 构造
  • 主要方法
  • 1、run()相关方法
  • 2、get()相关方法
  • 3、cancel(boolean t)方法
  • 使用Demo


一、简介

通过把普通任务封装成FutureTask来获取执行结果,同时还可以感知任务执行的异常,甚至还可以取消任务

采用异常调用思想,Netty、Dubbo中常见

二、继承关系图

未来任务java 未来的任务_FutureTask

  • @FunctionalInterface 声明为函数式接口,这个接口只有一个抽象方法
  • Future 未来接口
  • Runnable 线程接口
  • RunnableFuture 未来+线程接口组合
  • WaitNode是FutureTask的内类

三、存储结构

把线程转换成Callable线程,然后封装成FutureTask来进行操作,并且重写了run方法

四、源码分析

内部类
  • WaitNode内部类
static final class WaitNode {
    volatile Thread thread;
    volatile WaitNode next;
    WaitNode() { thread = Thread.currentThread(); }
}
属性
/* 
        * Possible state transitions:
        * NEW -> COMPLETING -> NORMAL
        * NEW -> COMPLETING -> EXCEPTIONAL
        * NEW -> CANCELLED
        * NEW -> INTERRUPTING -> INTERRUPTED
     */
private volatile int state;
// 任务初始化状态(新建或还没完成),#开始状态#
private static final int NEW          = 0; 
// 任务完成状态(任务已执行完成或者执行任务出现异常,但是还没有保存outcome字段)
// NEW到COMPLETING的状态很短,这是一个#中间状态#
private static final int COMPLETING   = 1; 
// 任务执行完成,并且任务执行结果已经保存到outcome字段,#最终状态#
private static final int NORMAL       = 2; 
// 任务执行异常,并且异常保存到了outcome字段,#最终状态#
private static final int EXCEPTIONAL  = 3; 
// 任务还没开始执行或者已经开始执行但是还没有执行完成的时候,
// 用户调用了cancel(false)方法取消任务且不中断任务执行线程,这个时候会转成这个状态,#最终状态#
private static final int CANCELLED    = 4; 
// 任务还没开始执行或者已经开始执行但是还没有执行完成的时候,
// 用户调用了cancel(true)方法取消任务且要中断任务执行线程,但是还没有中断任务执行线程之前
// 状态 NEW 转换为 INTERRUPTING ,#中间状态#
private static final int INTERRUPTING = 5; 
// 调用interrupt()中断任务执行线程之后会从INTERRUPT状态切换为INTERRUPTED,这是一个#最终状态#
private static final int INTERRUPTED  = 6; 

/** 真正的线程,运行完成(异常完成)后设置为null */
private Callable<V> callable;
/** 返回的结果,或抛出的异常 */
private Object outcome; // non-volatile, protected by state reads/writes
/** 任务的执行者,真正的线程运行后设置为null */
private volatile Thread runner;
/** 等待队列 */
private volatile WaitNode waiters;
构造
/** 构造方法一:把Callable包装成FutureTask */
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}
/** 构造方法二:把Runnable和V返回对象包装成Callable然后再包装成FutureTask */
public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}
主要方法
1、run()相关方法
  • run()方法:任务执行
  • set(V v )方法:任务正常完成,设置结果
  • setException(Throwable t)方法:任务异常完成,设置异常结果
  • finishCopletion()方法:任务完成后,执行此方法唤醒队列中其他线程
// 此方法还有一个runAndReset的protected修饰的方法,具有返回true和flase
public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        // state不是新建状态,或 原子更新runner属性为当前线程失败就返回,run失败
        return;
    try {
        // 获取实例线程
        Callable<V> c = callable;
        // 判断实例线程,不能为空,状态必须是NEW
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 执行实例线程任务,采用call的觉有返回值
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                // 任务执行失败,设置异常结果
                ran = false;
                setException(ex);
            }
            if (ran)
                // 任务执行成功,设置返回结果
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;//帮助GC
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            // 如果当前的任务线程出现中断,就进行处理
            handlePossibleCancellationInterrupt(s);
    }
}
/** 调用实例线程异常执行方法 */
protected void setException(Throwable t) {
    // 将状态从NEW设置为COMPLETING
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        // 设置返回值
        outcome = t;
        // 有序原子写state状态为EXCEPTIONAL
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        // 调用完成方法
        finishCompletion();
    }
}

/** 调用实例线程完成返回方法 */
protected void set(V v) {
    // 将状态从NEW设置为COMPLETING
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        // 设置返回值
        outcome = v;
        // 有序原子写state状态为NORMAL
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        // 调用完成方法
        finishCompletion();
    }
}

/** 状态为#最终状态#时,调动 :有疑问?什么鬼waiters,请去看get*/
private void finishCompletion() {
    // assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        // 置空队列
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
            for (;;) {
                // 调用者线程
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    // 如果调用者线程不为null,就唤醒它
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }

    // 钩子方法,子类重写
    done();

    // 设置实例线程为null
    callable = null;        // to reduce footprint
}
2、get()相关方法
  • get():获取返回结果,如果结果就会进入等待队列
  • awaitDone(boolean timed,long nanos);把当前线程加入到等待队列
  • report:获取返回结果
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        // 说线程是NEW或运行完成但是还没保存返回结果的时候
        // 就到队列中去等待 ,所以是这个时候
        s = awaitDone(false, 0L);
    return report(s);
}
/** 把当前线程加入到WaitNode等待队列 */
private int awaitDone(boolean timed, long nanos)
    // 只考虑get调用,是不带超时的
    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;
        // 如果状态大于COMPLETING了,就跳出循环并返回
        // 这里是自旋的出口
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        // 如果状态等于COMPLETING,
        // 说明任务快完成了,就差设置状态到NORMAL或EXCEPTIONAL和设置任务结果
        // 那么就让出CPU资源
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        // 如果队列为null,就初始化队列
        else if (q == null)
            // 用用当前线程去初始化
            // WaitNode() { thread = Thread.currentThread(); }
            q = new WaitNode();
        // 如果未进入队列
        else if (!queued)
            // 尝试CAS入队
            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);
        }
        // 阻塞当前线程(调用者线程)
        else
            LockSupport.park(this);
    }
}

/** get()方法中,确定过任务线程已经大于COMPLETING,然后就去取值 */
private V report(int s) throws ExecutionException {
    Object x = outcome;
    // 任务正常结束
    if (s == NORMAL)
        return (V)x;
    // 被取消了,抛CancellationException异常
    if (s >= CANCELLED)
        throw new CancellationException();
    // 执行异常,抛ExecutionException((Throwable)x)异常
    throw new ExecutionException((Throwable)x);
}
3、cancel(boolean t)方法
  • mayInterruptIfRunning:是否中断执行线程
public boolean cancel(boolean mayInterruptIfRunning) {
    // 把任务状态从NEW 修改为 INTERRUPTING(中间状态)或CANCELLED(完成状态)
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                                   mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        // 是否中断执行线程
        if (mayInterruptIfRunning) {
            try {
                // 获取执行线程
                Thread t = runner;
                if (t != null)
                    // 强制中断
                    t.interrupt();
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        // 调用任务完成方法
        finishCompletion();
    }
    return true;
}
使用Demo
  • 利用显示成的submit提交可以返回future来完成
public class FutureTaskTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        ExecutorService threadPool = new ThreadPoolExecutor(5,10,1000L,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5));
        List<Future<Integer>> list = new ArrayList<>();

        IntStream.range(0,10).forEach(i -> {
            Future<Integer> future = threadPool.submit(() -> {
                Thread.sleep(1000L);
                System.out.println(i);
                return i;
            });
            list.add(future);
        });
        int sum = 0;
        for (Future<Integer> future : list) {
            sum += future.get();
        }
        System.out.println(sum);
    }
}