首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

【Java并发】可随带结果的任务:Callable和Future

2012-09-06 
【Java并发】可携带结果的任务:Callable和Future任务?? ? ?Executor框架使用Runnable作为任务的基本抽象。Run

【Java并发】可携带结果的任务:Callable和Future
任务

?? ? ?Executor框架使用Runnable作为任务的基本抽象。Runnable确实有限的抽象,虽然能够产生一些边界效应,如记录日志文件或者将结果写入一个共享数据结构里,但是不能返回一个值或者抛出检测异常。

?? ? 很多任务会引起严重的计算延迟——执行DB查询,从网络上获取资源,复杂计算等。对于这些任务,Callable是更佳的抽象。

?? ? Runnable和Callable描述的是抽象的计算型任务,这些任务通常是有限的:有一个明确的开始点,而且最终会结束。一个Executor执行的任务的生命周期可有四个阶段:

created -->?submitted -->?started -->?completed.

?

Callable

?

包:java.util.concurrent类:public interface Callable<V>方法:V call() throws Exception

?

?? ? ?Callable Task是有lifecycle的,分别为created/submitted/started/completed(创建/提交/启动/完成)。

?? ? ?对于处在submitted与started间的task可以通过Future来cancel该task,对于已经started但是还没有completed的task,只能期望task能够响应interruption从而终止(Future依然调用cancel)。对于已经completed的task是无法被cancel的,此时如果调用cancel则会返回false(其实如果调用cancel返回false一般是因为该task已经completed)。


任务封装?? ? ? Executors提供了些工具方法用于将其他类型的任务(如Runnable、java.security.PrivilegedAction)封装成一个Callable。 public class Executors extends Object
//返回 Callable 对象,调用它时可运行给定的任务并返回 null。static Callable<Object> callable(Runnable task) //返回 Callable 对象,调用它时可运行给定的任务并返回给定的结果。static <T> Callable<T> callable(Runnable task, T result) 
【扩展】?Callable?callable(Runnable task, T result) ——适配器设计模式的应用

public static Callable<Object> callable(Runnable task) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<Object>(task, null);}public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result);}//Adapter类:实现目标接口,持有被适配者adaptee的引用,通过构造将被适配者实例传入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; }}?
Future?? ? ?描述了asynchronous computation task任务的生命周期,提供了如下功能 1.获取任务的结果 2.取消任务 3.获得任务进行状态(完成还是被取消)。

public interface Future<V>V get() throws InterruptedException,ExecutionExceptionV get(long timeout,TimeUnit unit)throws InterruptedException,             ExecutionException,             TimeoutExceptionboolean cancel(boolean mayInterruptIfRunning)boolean isCancelled()boolean isDone() 
get():如果任务已经完成,get会立即返回或者抛出异常;如果任务没有完成,get会阻塞直到它完成。ExecutionException:

Future继承结构

【Java并发】可随带结果的任务:Callable和Future

?创建描述任务的Future

方式1:将Callable或者Runnable提交给executor获得Future实例。

?

ExecutorService executor = ...Future f = executor.submit(Callable<T> task);Future f = executor.submit(Runnable task);Future f = executor.submit(Runnable task, T result);

方式2:使用给定的Callable或者Runnable来实例化FutureTask。

?

FutureTask

已实现的接口:Runnable、Future、RunnableFuture。

构造:可以使用FutureTask来包装Callable或Runnable对象。

?

//FutureTask一旦运行就执行给定的 CallableFutureTask(Callable<V> callable) FutureTask(Runnable runnable, V result) 

要点:

1. 因为FutureTask实现了Runnable接口,可以可将FutureTask交由Executor执行,或者构造一个Thread。

2.?FutureTask的计算结果从运行计算的线程传送到需要这个结果的线程(调用get的线程),并保证这种传递建立在结果的安全发布基础上。

?

代码示例:利用FutureTask、Callable、Thread对耗时任务(如查询数据库)做预处理,在需要计算结果之前就启动计算。

(代码见ConcurrentSamples/simulate.futuretask.preload)

private final FutureTask<ProductInfo> future =             new FutureTask<ProductInfo>(new Callable<ProductInfo>(){                public ProductInfo call() throws DataLoadException{                    ProductInfoLoader loader = new ProductInfoLoader();                    return loader.load();//加载数据:查询数据库                }            });    private final Thread t = new Thread(future);        public void start(){        t.start();    }        public ProductInfo load() throws DataLoadException, InterruptedException{        try {            return future.get();        } catch (ExecutionException e) {            Throwable cause = e.getCause();            if(cause instanceof DataLoadException)                throw (DataLoadException)cause;            else                throw launderThrowable(e);        }    }

热点排行