IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JDK8 FutureTask源码分析 -> 正文阅读

[Java知识库]JDK8 FutureTask源码分析

一、概述

1.1 FutureTask能够解决什么问题

  • 内部持有Callable类型变量,可以获取线程返回值
  • 实现了Runnable接口,可以提交到线程池中运行,也可以直接被Thread执行
  • 实现了Future接口,调用get时可以阻塞到获取结果,也可以提前取消任务

1.2 FutureTask如何保证线程安全

使用了cas

二、关键知识点

  • 状态的含义以及转移方式(set、setException)
  • 任务启动调用了run方法,run的内部逻辑
  • 想要获取任务结果的线程调用get方法被阻塞,其阻塞逻辑(awaitDone)
  • 阻塞等待队列的添加、移除(removeWaiter)、唤醒(finishCompletion)逻辑
  • cancel逻辑

三、状态分析

一个FutureTask任务有七种状态,每种状态含义以及状态转换图如下

状态对应值含义前一状态
NEW0新的任务 或者 还没被执行完的任务,是初始状态
COMPLETING1中间态-完成call逻辑。任务已经执行完成 或者 发生异常,但异常还没保存到outcome。state > COMPLETING 代表任务已完成(正常完成,执行异常,被取消)NEW
NORMAL2最终态-完成。任务执行完成,且执行结果保存到outcome字段。COMPLETING
EXCEPTIONAL3最终态-发生异常。执行发生异常并将异常信息保存到outcome字段。COMPLETING
CANCELLED4最终态-取消任务。任务处在NEW状态时,用户调用了cancel(false)方法,取消任务且 不中断任务执行线程NEW
INTERRUPTING5中间态-中断中。任务处在NEW状态,用户调用了cancel(true)方法,取消任务并且想要中断任务线程但还没中断线程之前NEW
INTERRUPTED6最终态-已中断。任务处在INTERRUPTING,在执行完interrupted()后,线程被中断INTERRUPTING

在这里插入图片描述

四、使用示例

三种使用方式:

  • FutureTask + Thread
  • FutureTask + ExecutorService
  • Future + ExecutorService

代码如下:

public class FutureTaskTest {
    static final Callable<Integer> callable = () -> {
        Thread.sleep(100);
        return 1;
    };

    private void futureAndExecutorService() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();

        Future<Integer> submit = executorService.submit(callable);

        System.out.println(submit.get());

        executorService.shutdown();
    }
    private void futureTaskAndThread() throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(callable);

        Thread thread = new Thread(futureTask);

        thread.start();

        System.out.println(futureTask.get());
    }
    private void futureTaskAndExecutorService() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();

        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        executorService.submit(futureTask);

        System.out.println(futureTask.get());

        executorService.shutdown();
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTaskTest task = new FutureTaskTest();
        task.futureTaskAndThread();
        task.futureTaskAndExecutorService();
        task.futureAndExecutorService();
    }
}

五、源码分析

package java.util.concurrent;
import java.util.concurrent.locks.LockSupport;

public class FutureTask<V> implements RunnableFuture<V> {
    /**
     * <img src="./img/FutureTask状态图.png" />
     */
    // 当前任务状态,是volatile类型
    private volatile int state;
    // 新的任务 或者 还没被执行完的任务,是初始状态
    private static final int NEW          = 0;
    // state > COMPLETING 代表任务已完成(正常完成,执行异常,被取消)
    // 中间态-完成。任务已经执行完成 或者 发生异常,但异常还没保存到outcome。中间态,比较短 NEW->COMPLETING
    private static final int COMPLETING   = 1;
    // 最终态-完成。任务执行完成,且执行结果保存到outcome字段。从COMPLETING->NORMAL
    private static final int NORMAL       = 2;
    // 最终态-发生异常。执行发生异常并将异常信息保存到outcome字段。从从COMPLETING->EXCEPTIONAL
    private static final int EXCEPTIONAL  = 3;
    // 最终态-取消任务。任务处在NEW状态时,用户调用了cancel(false)方法,取消任务且 不中断任务执行线程 NEW->CANCELLED
    private static final int CANCELLED    = 4;
    // 中间态-中断中。任务处在NEW状态,用户调用了cancel(true)方法,取消任务并且想要中断任务线程但还没中断线程之前 NEW->INTERRUPTING
    private static final int INTERRUPTING = 5;
    // 最终态-已中断。任务处在INTERRUPTING,在执行完interrupted()后,线程被中断,状态转换 INTERRUPTING->INTERRUPTED
    private static final int INTERRUPTED  = 6;

    /**
     * 内部持有的callable任务,运行后清空
     */
    private Callable<V> callable;
    /**
     * get中返回的结果或者抛出的异常
     * 不是volatile类型,被state的读写保护
     */
    private Object outcome;
    /**
     * 运行callable的线程
     */
    private volatile Thread runner;
    /**
     * 使用Treiber栈保存线程
     */
    private volatile WaitNode waiters;

    /**
     * 返回结果或者抛出异常
     * @param s 最终完成的状态
     */
    @SuppressWarnings("unchecked")
    private V report(int s) throws ExecutionException {
        Object x = outcome;
        // 正常结束,则返回结果
        if (s == NORMAL)
            return (V)x;
        // 大于等于CANCELLED(事实上只有CANCELLED,两个中断状态在进入该方法前就抛出了异常)
        if (s >= CANCELLED)
            throw new CancellationException();
        // EXCEPTIONAL状态抛出异常
        throw new ExecutionException((Throwable)x);
    }

    /**
     * 构造
     * @param callable callable接口
     */
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;
    }

    /**
     * 构造,这里用了适配器模式,将runnable转成callable
     * @param runnable runnable
     * @param result 记录执行结果
     */
    public FutureTask(Runnable runnable, V result) {
        // 适配器模式,runnable转callable
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;
    }

    /**
     * INTERRUPTING(5)、INTERRUPTED(6)、CANCELLED(4) 都是调用cancelled方法后的状态
     * @return 是否
     */
    public boolean isCancelled() {
        return state >= CANCELLED;
    }

    /**
     * 除了new都是任务已完成
     * @return 是否
     */
    public boolean isDone() {
        return state != NEW;
    }

    /**
     * 取消任务,必须在NEW状态才可以
     * 任务取消后,被阻塞的线程会被唤醒,得到get返回null
     * @param mayInterruptIfRunning 是否中断
     * @return 是否取消成功
     */
    public boolean cancel(boolean mayInterruptIfRunning) {
        // 如果不是NEW状态或者cas更改状态失败,则返回false
        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;
                    // 如果t不为null,则中断执行任务的线程t
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    // 将状态最终变为INTERRUPTED
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            // 如果不中断直接执行,则唤醒所有等待线程
            finishCompletion();
        }
        return true;
    }

    /**
     * 获取结果,任务未结束前调用线程被阻塞
     */
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        // 假如状态为NEW或者COMPLETING,则阻塞在这里
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        // 返回结果或抛出异常
        return report(s);
    }


    /**
     * 阻塞指定时间
     * @param timeout 阻塞时间
     * @param unit 单位
     * @return 任务结果
     */
    public V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        // 超时返回的状态一定小于COMPLETING
        if (s <= COMPLETING &&
                (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }

    /**
     * 可以被子类重写,在唤醒所有线程后调用
     */
    protected void done() { }

    /**
     * 状态变更,记录执行结果到outcome上,并唤醒所有线程
     * @param v 执行结果
     */
    protected void set(V v) {
        // 状态从NEW->COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            // 执行结果赋值到outcome
            outcome = v;
            // 将状态从COMPLETING->NORMAL
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            // 唤醒所有等待线程
            finishCompletion();
        }
    }

    /**
     * 执行失败抛出异常后调用此方法
     * @param t 捕获的异常
     */
    protected void setException(Throwable t) {
        // 将NEW->COMPLETING 中间态
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            // 记录异常信息到outcome
            outcome = t;
            // 将状态变为COMPLETING->EXCEPTIONAL
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL);
            // 唤醒所有等待的线程
            finishCompletion();
        }
    }

    /**
     * 线程启动时调用的方法
     * 启动时,状态必须是NEW
     * callable为null的话不报错,不执行
     * 执行一次后就不能再调用run方法了
     */
    public void run() {
        // 启动时,状态必须是 NEW ,并且cas将runner代表的线程赋值为当前线程成功
        if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                        null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            // callable不为null且状态为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)
                    // 状态变更,记录执行结果到outcome上,并唤醒所有线程
                    set(result);
            }
        } finally {
            // 为了防止并发调用run方法,在state变成最终态之前,runner必须不是null
            runner = null;
            int s = state;
            // 如果发现被取消并中断了
            if (s >= INTERRUPTING)
                // 让调用cancelled的线程先执行,直到将状态变成INTERRUPTED
                handlePossibleCancellationInterrupt(s);
        }
    }

    /**
     * 与run方法基本相同,不过该方法可以重复调用,
     * 如果无异常、取消、中断,state不会被更新,一直保持为NEW。
     */
    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 {
            runner = null;
            s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
        return ran && s == NEW;
    }

    /**
     * 保证run或runAndReset方法在cancelled(true)方法结束后结束
     * 当发现状态为INTERRUPTING的时候,让出cpu资源,直到cancelled把状态变为INTERRUPTED
     */
    private void handlePossibleCancellationInterrupt(int s) {
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield();
    }

    /**
     * 单链表
     */
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

    /**
     * 唤醒所有等待的线程(唤醒后在awaitOne中继续执行),执行done方法,callable属性重新赋值为null
     */
    private void finishCompletion() {
        // assert state > COMPLETING;
        // cas重试
        for (WaitNode q; (q = waiters) != null;) {
            // 将waiters头结点从指向q变成指向null
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                // 将等待队列中所有的节点唤醒
                for (;;) {
                    Thread t = q.thread;
                    // 当前节点不再持有线程并唤醒线程
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    // 指针后移,到结尾则退出
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }

        done();

        callable = null;        // to reduce footprint
    }

    /**
     * 等待任务执行完成 或者 中断 或者 超时
     * 状态为NEW的节点被阻塞
     * 被唤醒后,
     * 如果中断,则移除等待队列并抛出异常
     * 如果处于COMPLETING状态,逻辑执行完但还没将结果放到outcome,则让出CPU
     * 如果大于COMPLETING状态,相当于CANCELLED、NORMAL、EXCEPTIONAL,则返回状态
     * @param timed true 则等待,false不等待
     * @param nanos time 如果timed为true,则等待nanos时长
     * @return 完成后的state
     */
    private int awaitDone(boolean timed, long nanos)
            throws InterruptedException {
        // 等待结束时间
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        // 当前等待线程包装成的等待节点
        WaitNode q = null;
        // 当前节点是否进入了等待队列
        boolean queued = false;
        // 自旋
        for (;;) {
            // 获取并清除中断状态。如果已经中断了,则移除节点并抛出异常
            // cancelled(true)后,会在这个方法结束
            if (Thread.interrupted()) {
                // 移除等待的waitNode
                removeWaiter(q);
                throw new InterruptedException();
            }
            // 获取当前状态
            int s = state;
            // 如果状态大于COMPLETING,说明任务处于最终态或者中断中
            // cancelled(false)后,会在这个方法结束
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            // 任务执行完了,但还没将结果放到outcome中,让出当前CPU,让执行任务的线程调用run方法使用CPU
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            // 如果状态为NEW,并且q为null,则让q指向新建的等待节点
            else if (q == null)
                q = new WaitNode();
            // 如果状态为NEW,并且q不为null,并且queued为false,也就是当前节点没进入等待队列。
            else if (!queued)
                // 头插法,当前节点的后继为原来的头,并且将头指向当前节点,返回cas是否成功
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                        q.next = waiters, q);
            // 如果状态为NEW,并且q不为null,queued为true,并设置了阻塞等待时间
            else if (timed) {
                nanos = deadline - System.nanoTime();
                // 如果超时了
                if (nanos <= 0L) {
                    // 移除队列中的节点q
                    removeWaiter(q);
                    // 返回当前状态
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            //如果状态为NEW,并且q不为null,queued为true,并且没设置阻塞时间,则直接阻塞
            else
                // 阻塞当前线程
                LockSupport.park(this);
        }
    }

    /**
     * 将node的thread置为null,并移除等待队列中thread为null的节点
     * @param node 被移除的节点
     */
    private void removeWaiter(WaitNode node) {
        if (node != null) {
            // node拥有的线程变为null
            node.thread = null;
            retry:
            for (;;) {          // restart on removeWaiter race
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    // s为q的后继
                    s = q.next;
                    // 如果q拥有的thread不是null
                    if (q.thread != null)
                        // 历史节点变为q
                        pred = q;
                    // 如果q拥有的thread是null(说明q是应该被移除的节点) 且 历史节点不为null(q不是头结点)
                    else if (pred != null) {
                        // q的前驱的后继指向q的后继,说明q移除了队列
                        pred.next = s;
                        // 如果pred拥有的线程变为null,说明pred的节点应该被移除
                        if (pred.thread == null) // check for race
                            // 外层循环执行continue,内层停止循环。又要从头开始走一次循环,目的将pred也移除队列
                            continue retry;
                    }
                    // 如果q拥有的线程为null,并且pred为null(说明q为头结点,并且是应该被移除的节点)
                    // cas将waiter(也就是头结点)指向s(q的后继),相当于将node节点出队了
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                            q, s))
                        continue retry;
                }
                // 假如遍历到结尾,也不存在thread为null的节点,则停止循环
                break;
            }
        }
    }

    // Unsafe mechanics
    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);
        }
    }

}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:26:14  更:2022-05-09 12:27:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:02:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码