【多线程研究专题三】【FutureTask与Callable的本质】

来源:互联网 发布:mac 微软雅黑字体关了 编辑:程序博客网 时间:2024/06/15 09:58
吐槽:以前看了好多文章和书籍讲FutureTask,讲的很细,但不得要领,还是会忘。绝知此事要躬行,还是得自己亲自分析下源码。

1、FutureTask本质上是Runnable和Callable的实现类,就是一个任务类,主函数也是run()。
2、FutureTask实现了异步任务,怎么实现的?是因为Callable?
      不是。Callable.call()与Runnable.run()只是一个很普通的方法,是同步方法。异步方法是因为FutureTask的实现机制,使用了Guard Suspension模式。

下面说下Guard Suspension模式的核心思想,以及Future是如何实现的:

GS模式作用:把同步方法,变为异步方法。
GS模式思想:线程A执行与一般同步方法无异,主要是线程B(异步任务,如FutureTask所在的线程)的执行不一样:异步任务的get()方法调用wait()方法进入wait状态(java有多种实现),等待同步方法call()执行结束(在线程B中运行),通知get方法取消wait状态。这就是GS的主要思想。
示意图如下:



从上图可见,run()和get()是主要角色,run的代码如下:

set()其实很简单,就是返回outcome结果,并调用finishCompletion(),通知get()方法,取消wait状态。


再看下get(),awaitDone()就是进入了wait()状态。其实现是一个for(;;)循环。对应上面的finishCompletion(),我们只需要关注思想,先不管具体实现。
反正awatiDone()的无限循环会被finishCompletion()打破。然后调用report()

   publicVget()throwsInterruptedException, ExecutionException {
       ints=state;
       if(s<=COMPLETING)
           s= awaitDone(false, 0L);
       returnreport(s);
    }
report()实现如下。就是把set()里面设置的outcome传给x,然后返回。
   @SuppressWarnings("unchecked")
   privateVreport(ints)throwsExecutionException {
        Objectx=outcome;
       if(s==NORMAL)
           return(V)x;
       if(s>=CANCELLED)
           thrownewCancellationException();
       thrownewExecutionException((Throwable)x);
    }

小结:
1. FutureTask的核心思想是:通过awaitDone()和finishCompletion()实现异步操作。
2. 第1点,被封装为get()/set()。其中get()被外部线程A调用,set()被线程B--FutureTask的run()调用。
3.Callable的call()本质上是同步方法。
4.FutureTask的主函数只运行callable方法,Runnable.run()是通过一个adapter转为Callable的()。
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

Executors.callable定义如下:
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }

0 0
原创粉丝点击