美文网首页
JDK1.8 Callable、Future和FutureTas

JDK1.8 Callable、Future和FutureTas

作者: 南风nanfeng | 来源:发表于2018-11-23 17:49 被阅读36次

线程回顾

回顾一下线程创建的两种方式:
第一、继承Thread类,重写run方法。
第二、实现Runnable接口,实现run方法。
这二者的区别就是类只能单继承,接口可以多重继承,也可以多重实现。

Callable接口

这两种方式功能上没有任何差异,且都存在一些缺陷:
第一、线程执行后,无法返回执行结果。
第二、异常抛不出来,只能线程内处理。

针对这两个问题,jdk1.5后,Doug Lea在java.util.concurrent包提出了Callable接口和Future接口解决了这些问题。Callable接口代表接收返回结果的任务,Future接口代表对具体任务结果的查询,如Callable、Runnable任务是否完成、取消、以及获取结果。

下面对比Runnable、Callable接口,显而易见,Callable接口接收泛型作为返回数据类型,方法体抛出异常。

public interface Runnable {
    public abstract void run();
}

public interface Callable<V> {
    V call() throws Exception;
}

Future接口

Future接口表示获取异步任务的返回结果。提供了基本方法来判断异步任务是否完成。返回结果仅在任务完成后获取的到,如果任务未完成,获取结果方法则阻塞知道任务完成为止。当然,也可以取消任务执行。当一个任务执行完成,则无法被取消。

public interface Future<V> {

    /**
     * 取消执行中的任务,任务执行完成,则取消失败,返回false。
     * 如果任务没有调用start方法,执行cancel方法,则任务永远不会被执行。
     *
     * cancel方法被调用,isDone方法中会返回true,isCanceled也会返回true。
     * 参数mayInterruptIfRunning 为true表示线程执行中应该被中断,否则,执行中线程将继续直到完成
     */
    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    /**
     * 线程完成则返回true。若线程被停止、抛出异常或者取消,也会返回true。
     */
    boolean isDone();

    /**
     * 等待任务执行完成才会返回执行结果
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 指定等待超时时间
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

FutureTask

Future是接口,无法直接创建类,因此有了FutureTask类。uml类图如下:


futuretask.jpg

FutureTask同时实现了Future和Runnable接口,有两个构造方法:
第一、传入Callable<V>,很明显Callable的泛型就是任务的返回结果类型。
第二、传入Runnable和V,Runnable接口是void类型,第二参数泛型V表示任务执行结果数据类型。

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;      
    }

    public FutureTask(Runnable runnable, V result) {
        //此处实际上也是构造了一个Callable对象,看下面源码
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       
    }

    // 构建实现Callable类
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }

    //该类实现Callable接口,构建方法传入Runnable、T
    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }

        // 改方法调用Runnable的run方法,并不是作为异步任务交给OS调用,仅在当前线程执行一遍run方法,然后同步返回result的结果。
        public T call() {
            task.run();
            return result;
        }
    }

注意上述两个构造方法异同,第一种,call方法直接返回计算结果,这个没有一点问题;但是第二种,传入Runnable接口和返回值T,这个T是预设的返回值,什么意思呢,就是说构造方法传入什么值,它就返回什么值,可能与任务执行结果有出入,这点值得注意。

相关文章

网友评论

      本文标题:JDK1.8 Callable、Future和FutureTas

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