美文网首页
Future备忘录

Future备忘录

作者: oceanLong | 来源:发表于2019-01-22 20:08 被阅读5次

    概述

    Future是一个接口,它的主要目的,是为了我们能够方便的控制在线程中的任务的进度。在实际使用中,它常与Callable一起使用。本文主要为了理清,Java中,线程任务的各种类的关系。

    Runable与Callable

    Runable与Callable都是纯接口,它是Java中,对于任务的抽象概念。其中,我们看一看它们的源码就可以知道了。

    public interface Runnable {
     abstract void run();
    }
    
    public interface Callable<V> {
    
        V call() throws Exception;
    }
    

    Runable与Callable的差别就是一个有返回,一个没返回。

    Future

    Future是线程运行任务的控制器,我们可以通过它,控制任务的启停,获取任务的状态,获取任务返回的结果。

    先看源码:

    public interface Future<V> {
    
        boolean cancel(boolean mayInterruptIfRunning);
    
        boolean isCancelled();
    
        boolean isDone();
    
        V get() throws InterruptedException, ExecutionException;
    
        V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    }
    

    我们可以看到Future提供的API。其中,值得注意的是,get方法会阻塞当前线程。

    在Java中,提供了一种基本的实现:FutureTask
    FutureTask实现了RunnableFuture<V>接口,而 RunnableFuture<V>则是继承了,RunnbleFuture<V>

    public interface RunnableFuture<V> extends Runnable, Future<V> {
        /**
         * Sets this Future to the result of its computation
         * unless it has been cancelled.
         */
        void run();
    }
    

    FutureTask提供了两个构造方法:

    
        public FutureTask(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW;       // ensure visibility of callable
        }
    
       
        public FutureTask(Runnable runnable, V result) {
            this.callable = Executors.callable(runnable, result);
            this.state = NEW;       // ensure visibility of callable
        }
    

    其中输入RunnableFutureTask的内部也会转化为Callable

    
        private static final class RunnableAdapter<T> implements Callable<T> {
            private final Runnable task;
            private final T result;
            RunnableAdapter(Runnable task, T result) {
                this.task = task;
                this.result = result;
            }
            public T call() {
                task.run();
                return result;
            }
        }
    
    

    所以,我们使用时,是将需要执行的逻辑放在Callable中,然后
    当我们将FutureTask传入线程池,或者新线程时,因为它本身具有Runable的接口,所以可以像正常Runnable那样执行。又因为其持有了一个Callable。所以,当任务执行完时,会有输出结果,FutureTask会保存这个结果,等待外部来取。

    如果此时任务尚未执行完成,外部就企图获取结果,会阻塞当前线程。

    这个地方看起逻辑复杂,其实只要看一眼源码就很清楚了。

        public V get() throws InterruptedException, ExecutionException {
            int s = state;
            if (s <= COMPLETING)
                s = awaitDone(false, 0L);
            return report(s);
        }
    
        public V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
            if (unit == null)
                throw new NullPointerException();
            int s = state;
            if (s <= COMPLETING &&
                (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
                throw new TimeoutException();
            return report(s);
        }
    

    其中awaitDone就是一个封装了超时和中断的await
    当任务执行完成后,阻塞结果,返回结果。

    相关文章

      网友评论

          本文标题:Future备忘录

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