Android之多线程解析(二)之Runnable、Callable、FutureTask

来源:互联网 发布:兄弟连nginx视频教程 编辑:程序博客网 时间:2024/06/07 01:37

与多线程相关的方法—Callable,Future以及FutureTask

除了上文中一直分析的Runnable之外,Java中还存在Callbale,Future,FutureTask与多线程相关的概念,与Runnable不同的则是这三个方法只能用于线程池中,Runnable则可以同时在运用在Thread和线程池中。

Callable与Runnable功能相似,不同在与Callable是一个泛型接口,他有一个泛型参数V,该接口中有一个返回值(类型为V)的call()函数,而Runnable的run函数不能将结果返回到客户程序中:

public interface Callable<V>{    //返回V类型的结果    V call() throws Exception;}//为加深理解,假如Runnable的源码作为对比public interface Runnable{    //返回V类型的结果    public abstract void run();}

博客看到此处,即对Runnable以及Callable有了比较大致的了解,但是这两种机制存在着一个无法避免的缺陷,即一旦使用后就很难做到有效的控制。而Future的出现即解决了这种问题,Future为线程池制订了可管理的任务标准。Future提供了对Runnable或者Callable的任务的执行结果进行管理(取消,查询是否完成,获取结果,设置结果;分别对应着cancel,isDone,get,set函数,且get函数调用后会发生阻塞,直到执行完成返回结果)。Future声明如下:

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

Future只是定义了一些规范的接口,FutureTask则是具体的实现类。FutureTask实现了RunnableFuture,而RunnableFuture实现了Runnable又实现了Future这两个接口,因此FutureTask同时具有两者的能力。FutureTask代码如下:

public class FutureTask<V> implements RunnableFuture<V>{    //代码省略}

再看RunnabelFuture类定义:

public class RunnabelFuture<V> implements Runnable,Future<V>{    void run();}

FutureTask会像Thread包装Runnable那样对Runnable和Callbale进行包装,Runnbale与Callbale由构造函数注入。

public FutureTask(Callable<V> callable){    if(callable==null) throws 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}

由上述代码即可看出,无论在构造函数中传输runnable或callable对象,都会被转换为callable对象,即可知道最终都是对Callable对象进行操作,该适配函数的实现如下:

public static <T> Callable<T> callable(Runnable task,T result){    if(task==null) throws 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()获取执行结果,该函数会一直阻塞到结果返回。因此,FutureTask既是Future,Runnable,又包装了Callable,即为两者的合体
下面通过一个Java程序简单演示Runnable,Callable,FutureTask的运用:

public class FutureDemo {    static ExecutorService mExecutor=Executors.newSingleThreadExecutor();    public static void main(String[] args){        try {            FutureWithRunnable();            FutureWithCallable();            FutureWithFutureTask();        } catch (Exception e) {            // TODO: handle exception        }    }    private static void FutureWithRunnable() throws InterruptedException,ExecutionException{        Future<?> result=mExecutor.submit(new Runnable() {            public void run() {                // TODO Auto-generated method stub                fibc(20);            }        });        System.out.println("Future result from Runnable : "+result.get());    }    private static void FutureWithCallable() throws InterruptedException,ExecutionException{        Future<Integer> result2=mExecutor.submit(new Callable<Integer>(){            public Integer call() throws Exception {                // TODO Auto-generated method stub                return fibc(20);            }        });        System.out.println("Future result from Callable : "+result2.get());    }    private static void FutureWithFutureTask() throws InterruptedException,ExecutionException{        FutureTask<Integer> futuretask=new FutureTask<Integer>(                new Callable<Integer>() {                    public Integer call() throws Exception {                        return fibc(20);                    }                });        mExecutor.submit(futuretask);        System.out.println("Future result from FutureTask : "+futuretask.get());    }    private static int fibc(int num){        if(num == 0)            return 0;        if(num == 1)            return 1;        return fibc(num-1)+fibc(num-2);    }}

运行结果为:
Future result from Runnable : null
Future result from Callable : 6765
Future result from FutureTask : 6765

由上述示例代码以及结果可以看出,以Runnable作为对象的执行后的结果无法通过get()函数方法获得。而使用Callable以及调用Callable的FutureTask可以通过get()函数获取执行后的结果。

原创粉丝点击