FutureTask解析

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

实现原理总结

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

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

FutureTask解析_第1张图片
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 future = service.submit(task1);
         * service.shutdown();
         */


        /**
         * 第二种方式: FutureTask + ExecutorService
         * ExecutorService executor = Executors.newCachedThreadPool();
         * Task task = new Task();
         * FutureTask futureTask = new FutureTask(task);
         * executor.submit(futureTask);
         * executor.shutdown();

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

     Future submit(Callable task);
    Future submit(Runnable task);
     Future submit(Runnable task, T result);

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

参考

    1. 深入学习FutureTask
    1. 并发编程的艺术
    1. Executor, ExecutorService 和 Executors 间的不同

你可能感兴趣的:(FutureTask解析)