FutureTask源码解析

FutureTask源码解读

如有问题或者错误请及时留言联系作者
例如:源码解读错误/源码没解释清楚/自己没弄明白等等



前言

在 Java 1.5 我们创建线程的方式是继承Thread类或者实现Runnable接口,但是这两种方法都无法返回结果所以Doug Lea 在Jdk1.5引入了Callable接口以及FutureTask类来完成返回结果的获取,接下来就和我一起来探究FutureTask的原理吧


提示:以下是本篇文章正文内容,下面案例可供参考

一、FutureTask使用演示

   FutureTask<String> futureTask = new FutureTask<>(() -> {
            System.out.println("futureTask");
            TimeUnit.SECONDS.sleep(10);
            return "JJKING";
        });


        new Thread(futureTask).start();
        
        System.out.println(futureTask.get());

返回结果:
在这里插入图片描述

我们可以看到引入了FutureTask我们就可以使用Callable接口来返回结果

二、构造方法

1.Runnable构造方法

    public FutureTask(Runnable runnable, V result) {
        //将runable接口转换为callable因为FutureTask里面存储的是Callable变量
        this.callable = Executors.callable(runnable, result);
        //设置任务运行状态为未运行态
        this.state = NEW;
    }
 public static <T> Callable<T> callable(Runnable task, T result) {
        //对任务进行判空操作
        if (task == null)
            throw new NullPointerException();
       //使用适配器设计模式把Runnable适配成Callable     
        return new RunnableAdapter<T>(task, result);
    }
 static final class RunnableAdapter<T> implements Callable<T> {
        //保存的Runnable接口
        final Runnable task;
        //保存的返回值
        final T result;
        //如何适配的就是适配器RunableAdapter实现Callable接口并且把
        //Runnable 和结果设计成成员变量保存起来
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        //调用的时候直接调用的Runnable的run方法运行
        public T call() {
            task.run();
            return result;
        }
    }

2.Callable构造方法

 public FutureTask(Callable<V> callable) {
        //对传入的Callable实例机型判空
        if (callable == null)
            throw new NullPointerException();
        //给成员变量callable赋值为传过来的参数    
        this.callable = callable;
        //设置任务运行状态为未运行状态
        this.state = NEW;     
    }

2.变量解读

    //当前任务的状态使用state变量来表示(使用了volatile来保证多线程下的可见性)
    private volatile int state;
    //New:当前任务还未执行
    private static final int NEW          = 0;
    //COMPLETING:当前任务即将完成但是还没有完成
    private static final int COMPLETING   = 1;
    //NORMAL:当前任务正常结束
    private static final int NORMAL       = 2;
    //EXCEPTIONA:当前任务异常结束
    private static final int EXCEPTIONAL  = 3;
    //CANCELLED:当前任务已被取消
    private static final int CANCELLED    = 4;
    //INTERRUPTING:当前任务正处于中断中
    private static final int INTERRUPTING = 5;
    //INTERRUPTED:当前任务已被中断
    private static final int INTERRUPTED  = 6;

     
    //实现任务的Callable接口使用callable变量来保存 
    private Callable<V> callable;
    //接收结果的对象(使用Object类型注意有可能结果有异常)
    //todo: 问题1:为什么outcome不需要volatile修饰
    private Object outcome; 
    //当前执行任务的线程
    private volatile Thread runner;

    /**
     * waiters(由于有多个线程可能get所以使用WaitNode来存储多个线程)
     */
    private volatile WaitNode waiters;

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

3.代码debug演示

  FutureTask<String> futureTask = new FutureTask<>(() -> {
            System.out.println("futureTask");
            TimeUnit.SECONDS.sleep(10);
            return "JJKING";
        });
        
        System.out.println(futureTask.get());

总结

提示:这里对文章进行总结:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FutureTask是一个实现了RunnableFuture接口的类,它继承了Runnable和Future接口。因此,FutureTask既可以被当作一个Runnable来使用,也可以被当作一个Future来使用。 FutureTask实现了Future接口,完成了对Future接口的基本实现。除了实现了Future接口以外,FutureTask还实现了Runnable接口,这意味着它可以交由Executor执行,也可以直接用线程调用执行(futureTask.run())。 FutureTask具有三种执行状态:未启动、已启动和已完成。未启动指的是在调用run()方法之前,FutureTask处于未启动状态。已启动指的是FutureTask对象的run方法正在执行过程中,FutureTask处于已启动状态。已完成指的是FutureTask正常执行结束,或者被取消,或者执行过程中抛出异常而导致中断而结束。 在ThreadPoolExecutor的submit方法中,返回的是一个Future的实现,而这个实现就是FutureTask的一个具体实例。FutureTask帮助实现了具体的任务执行,并与Future接口中的get方法关联起来。 总结起来,FutureTask是一个能够同时担任Runnable和Future角色的类,它可以作为一个任务提交给线程池执行,也可以通过get方法来获取任务执行的结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【第十二篇】Java 线程池FutureFutureTask【重点】](https://blog.csdn.net/weixin_42039228/article/details/123198358)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [FutureTask简介](https://blog.csdn.net/u014516601/article/details/125123415)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值