Java中Callable和Future——简介

来源:互联网 发布:蚂蚁金服 基金知乎 编辑:程序博客网 时间:2024/06/14 06:59

一、Java线程实现基础


java中实现一个线程的方法是继承(extends)Thread类或者实现(implements)Runnable接口(我个人认为通过线程池启线程也算是)。

继承Thread类:

class A extends Thread{        @Override        public void run() {            //TODO         }    }

实现Runnable接口:

class B implements Runnable{        @Override        public void run() {            //TODO         }    }

抑或分别使用匿名内部类,如下:

new Thread(){    public void run() {       //TODO 操作    };}.start();
new Thread(    new Runnable() {        @Override        public void run() {            //TODO 操作        }    }).start();

其实Thread类自身就实现了Runnable接口:

public class Thread implements Runnable{}

二、Callable和Runnable


CallableRunnable接口申明定义分别如下:

/** * A task that returns a result and may throw an exception. * Implementors define a single method with no arguments called * {@code call}. * * <p>The {@code Callable} interface is similar to {@link * java.lang.Runnable}, in that both are designed for classes whose * instances are potentially executed by another thread.  A * {@code Runnable}, however, does not return a result and cannot * throw a checked exception. * * <p>The {@link Executors} class contains utility methods to * convert from other common forms to {@code Callable} classes. * */@FunctionalInterfacepublic interface Callable<V> {    /**     * Computes a result, or throws an exception if unable to do so.     *     * @return computed result     * @throws Exception if unable to compute a result     */    V call() throws Exception;}
public interface Runnable {    public abstract void run();}

它们都只有一个方法。相对而言,我们对Runnable接口还是比较熟悉。如Callable接口注释所说,我们知道CallableRunnable类似,都是为其实例可能由另一个线程执行而设计。但是Callable接口是泛型形式,call()方法,有返回值且可抛出异常,即可返回线程执行结果。


三、Future和FutureTask


3.1、Future介绍:

Future可以对具体的Callable任务进行相关操作:取消/中断当前任务、查询任务是否完成、获取任务结果。其中get()方法会阻塞,直到任务完成返回结果,下一篇介绍其实现原理。Future声明如下(详细请见JDK文档):

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接口说明处已给出了伪代码来说明如何使用:

interface ArchiveSearcher { String search(String target); }class App {   ExecutorService executor = ...   ArchiveSearcher searcher = ...   void showSearch(final String target)       throws InterruptedException {     Future<String> future       = executor.submit(new Callable<String>() {         public String call() {             return searcher.search(target);// 异步线程处理搜索         }});     displayOtherThings(); // 在异步搜索的同时,在当前线程中,我们同时干别的事情,爽哉     try {       displayText(future.get()); // 通过Future获取异步任务结果     } catch (ExecutionException ex) { cleanup(); return; }   } }}

3.2、FutureTask介绍:

Future接口说明处同时也提到其具体实现类FutureTask。先看一下如下类图:

这里写图片描述

可见FutureTask则是一个RunnableFuture,而RunnableFuture则既继承了Runnbale又继承了Futrue

public interface RunnableFuture<V> extends Runnable, Future<V> {        void run();  }
public class FutureTask<V> implements RunnableFuture<V>{}

另,查看源码发现其构造函数依赖注入RunnbaleCallable,且Runnable会被Executors.callable()转换为Callable类型,即FutureTask最终都是执行Callable类型式任务:

这里写图片描述

public FutureTask(Callable<V> callable) {    if (callable == null)         throw new NullPointerException();    this.callable = callable;    this.state = NEW;       // ensure visibility of callable}/**当不需要返回值时,result可以传null*/ public FutureTask(Runnable runnable, V result) {      this.callable = Executors.callable(runnable, result);//被Executors.callable()转换为`Callable`      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);}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;        }        public T call() {            task.run();            return result;        }}

综上,可见FutureTask间接实现了Runnable,因此它既可以通过Thread来直接执行,又可以提交给ExecuteService来执行(并且还可以直接通过get()函数获取得到执行结果),上述Future示例伪代码部分可以改造如下:

FutureTask<String> future =   new FutureTask<String>(new Callable<String>() {     public String call() {       return searcher.search(target);   }}); executor.execute(future);

FutureTask<String> future =   new FutureTask<String>(new Callable<String>() {     public String call() {       return searcher.search(target);   }}); new Thread(future).start();//没使用线程池,只是示意可以这么用