Java中Callable和Future——简介

一、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.
 *
 */
@FunctionalInterface
public 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();//没使用线程池,只是示意可以这么用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值