美文网首页
FutureTask解析

FutureTask解析

作者: high_m | 来源:发表于2017-09-13 17:32 被阅读0次

    FutureTask除了实现Future接口外,还实现了Runnable接口。因此其除了能交给Executor执行,也可以由调用线程直接执行(FutureTask.run())。以下是个人的经验总结,也参考了网上不少的文章,参考详见文末列表。

    实现原理总结

    关于实现原理,建议先看深入学习FutureTask文中的Why章节。

    FutureTask类内部维护一个volatile int 类型的字段state,表示任务的执行状态。

    state状态uml图
    其中COMPLETING状态和INTERRUPTING状态是保持时间很短的中间状态NORMAL、EXCEPTIONAL、CANCELLED、INTERRUPTED是最终状态。

    另外在FutureTask的run方法中有以下代码片段:

    public void run() {
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return;
            //以下代码略
     }
    

    UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))方法用于原子性设置变量对象字段值。this表示当前FutureTask实例,runnerOffset表示要修改的字段(runner)偏移量,null表示未修改时的期望值,Thread.currentThread()表示修改后的目标值。看以下代码片段:

        /** The thread running the callable; CASed during run() */
        private volatile Thread runner;//表示执行Callable的线程
        private static final long runnerOffset;
        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class<?> k = FutureTask.class;
                runnerOffset = UNSAFE.objectFieldOffset
                    (k.getDeclaredField("runner"));
            }catch(Execption){
            }
        }
    
    

    另外,参考文中也提到

    发起任务线程跟执行任务线程通常情况下都不会是同一个线程,在任务执行线程执行任务的时候,任务发起线程可以查看任务执行状态、获取任务执行结果、取消任务等等操作。

    这正符合了Executor框架中对任务的创建与分离的基本思想。这样做,既能充分利用多核CPU带来的执行工作效率上的提升,也能更好的解耦工作便于理解和维护。

    常见使用方式

    参考1中已经提到常见的三种使用方式,这里主要指出一些特别之处。

            /**
             * 第一种方式:Future + ExecutorService
             * Task task = new Task();
             * ExecutorService service = Executors.newCachedThreadPool();
             * Future<Integer> future = service.submit(task1);
             * service.shutdown();
             */
    
    
            /**
             * 第二种方式: FutureTask + ExecutorService
             * ExecutorService executor = Executors.newCachedThreadPool();
             * Task task = new Task();
             * FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
             * executor.submit(futureTask);
             * executor.shutdown();
    

    第一种方式得到的异步结果对象future与第二种futureTask在本质上都是FutureTask类型,截止到JDK1.8

        <T> Future<T> submit(Callable<T> task);
        Future<?> submit(Runnable task);
        <T> Future<T> submit(Runnable task, T result);
    

    这些方法的返回对象类型都是FutureTask

    参考

    相关文章

      网友评论

          本文标题:FutureTask解析

          本文链接:https://www.haomeiwen.com/subject/krzksxtx.html