携带结果的任务callable与future

来源:互联网 发布:线切割如何编程链轮 编辑:程序博客网 时间:2024/05/01 19:13

Executor框架使用Runnable作为其基本任务表示形式。Runnable是一种有很大局限的抽象,它不能返回一个值或者抛出一个受检查的异常。

但是许多任务实际上都是存在延迟的计算,比如执行数据库查询,从网络上获取资源,或者计算某个复杂的功能。对于这些任务,就要Callable来显身手了。

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

Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务等。

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;}

ExecutorService中所有submit方法都将返回一个Future,从而将一个Runnable或Callable提交给Executor,并得到一个Future来获得任务执行结果或者取消任务。

示例:使用Future实现页面渲染器

public class FutureRenderer {    private final ExecutorService executorService = Executors.newFixedThreadPool(5);    public void renderPage(CharSequence source) {        final List<ImageInfo> imageInfoList = scanForImageInfo(source);        Callable<List<ImageData>> task = new Callable<List<ImageData>>() {            public List<ImageData> call() throws Exception {                List<ImageData> result = new ArrayList<ImageData>();                for (ImageInfo imageInfo:imageInfoList)                    result.add(imageInfo.downloadImage());                return null;            }        };        Future<List<ImageData>> future = executorService.submit(task);        renderText(source);        try {            List<ImageData> imageDatas = future.get();            for (ImageData data : imageDatas) {                renderImage(data);            }        } catch (InterruptedException e) {            Thread.currentThread().interrupt();            future.cancel(true);        } catch (ExecutionException e) {            e.printStackTrace();        }    }}

get方法的行为取决于任务的状态(尚未开始、正在运行、已完成)。如果任务已经完成,那么get会立即返回或者抛出一个Exception,如果任务没有完成,那么get将阻塞并直到任务完成。

还可以显式地为某个指定的Runnable或Callable实例化一个FutureTask(由于FutureTask实现了Runnable,因此可以将它提交给Executor来执行或者直接调用它的run方法)。

 ExecutorService executorService = Executors.newFixedThreadPool(5); FutureTask futureTask = new FutureTask(new Callable() {     @Override     public Object call() throws Exception {         return null;     }});executorService.submit(futureTask);//futureTask.run();

CompletionService

CompletionService将Executor和BlockingQueue的功能融合在一起。你可以将Callable任务提交给它来执行,然后使用类似于队列操作的take和poll等方法来获得已完成的结果。

示例:使用CompletionService实现页面渲染器

public class Renderer {    private final ExecutorService executorService;    public Renderer(ExecutorService executorService) {        this.executorService = executorService;    }    public void renderPage(CharSequence source) {        final List<ImageInfo> imageInfoList = scanForImageInfo(source);        CompletionService<ImageData> completionService = new ExecutorCompletionService<ImageData>(executorService);        for (final ImageInfo imageInfo : imageInfoList) {            completionService.submit(new Callable<ImageData>() {                public ImageData call() throws Exception {                    return imageInfo.downloadImage();                }            });        }        renderText(source);        try {            for (int i = 0, n = imageInfoList.size(); i < n; i++) {                Future<ImageData> f = completionService.take();                ImageData imageData = f.get();                renderImage(data);            }        } catch (InterruptedException e) {            Thread.currentThread().interrupt();            future.cancel(true);        } catch (ExecutionException e) {            e.printStackTrace();        }    }}

以上的代码从两个方面提高了页面渲染器的性能:
1. 为每一幅图像的下载都创建一个独立任务,并在线程池中执行它们,从而将串行的下载过程转换为并行的过程:这将减少下载所有图像的总时间。
2. 通过从CompletionService中获取结果以及使每张图片下载完成后立刻显示出来,能使用户获得一个更加动态和更加响应性的用户界面。

可以看摘取的部分源码:

public class ExecutorCompletionService<V> implements CompletionService<V> {    private final Executor executor;    private final AbstractExecutorService aes;    private final BlockingQueue<Future<V>> completionQueue;    /**     * FutureTask extension to enqueue upon completion     */    private class QueueingFuture extends FutureTask<Void> {        QueueingFuture(RunnableFuture<V> task) {            super(task, null);            this.task = task;        }        protected void done() { completionQueue.add(task); }        private final Future<V> task;    }    public ExecutorCompletionService(Executor executor) {        if (executor == null)            throw new NullPointerException();        this.executor = executor;        this.aes = (executor instanceof AbstractExecutorService) ?            (AbstractExecutorService) executor : null;        this.completionQueue = new LinkedBlockingQueue<Future<V>>();    }    public Future<V> submit(Callable<V> task) {        if (task == null) throw new NullPointerException();        RunnableFuture<V> f = newTaskFor(task);        executor.execute(new QueueingFuture(f));        return f;    }    public Future<V> submit(Runnable task, V result) {        if (task == null) throw new NullPointerException();        RunnableFuture<V> f = newTaskFor(task, result);        executor.execute(new QueueingFuture(f));        return f;    }    //...}

ExecutorCompletionService实现了CompletionService,并将计算部分委托给一个Executor。在构造函数中创建一个BlockingQueue来保存计算完成的结果。

Callable和Future总是如影随形,通过一个submit方法连接起来,使任务携带结果并随时取出结果成为可能。

0 0
原创粉丝点击