JUC-FutureTask

1. 当我们执行Future future = executorService.submit(myCallable);代码时,我们执行了什么?




FutureTask 类图

   从类图可以看到,FutureTask实现了两个基类(Future,Runnable);这里实现Future的目的,很明确,因为Future就是代表一个异步任务的未来结果;
而Runnable,这里是因为JUC线程池通用执行run方法来执行任务的,之所以这么说,有个结论需要记住,线程池执行Callable的时候,其实是通过FutureTask的run方法去执行的;

    //AbstractExecutorService.class
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    //AbstractExecutorService.class
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
    //FutureTask.class
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

   FutureTask的run代码如下:

    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    //这里去执行Callable的业务逻辑
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                //执行成功后直接将设置结果
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }




2. 当我们使用FutureTask时,我们想要什么?



   我们首先看看Future的API;

    /**
     * 尝试取消Callable的任务,因为Future是由Callable的索引的,所以功能上是没有问题的
     * mayInterruptIfRunning参数,如果是false,那么如果Callable业务在队列里还没有被执行到,那么任务会被取消
     * 那如果是true呢,那么如果Callable已经在执行中了,那么会将执行线程的中断标识置为true,当然如果业务逻辑不关心isInterrupt,起始对代码执行没有任何影响
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * 是否任务被取消
     */
    boolean isCancelled();

    /**
     * 是否任务已经完成
     */
    boolean isDone();

    /**
     * 首先这是一个阻塞方法,如果任务还没有被执行完
	 * 当任务执行完之后,会返回执行结果
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 有超时时间的get方法
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

   显然我们的目标是get()/get(long timeout, TimeUnit unit),当我们需要一个异步执行任务的结果时就可以通过get方法获取;但是缺点是阻塞当前线程,占用资源!

原文地址:https://www.cnblogs.com/IC1101/p/12804068.html