Chinaunix首页 | 论坛 | 博客
  • 博客访问: 69257
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 420
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-27 15:04
个人简介

记录,分享

文章分类

全部博文(43)

文章存档

2017年(24)

2015年(1)

2014年(18)

我的朋友

分类: Java

2014-06-27 16:01:06

一、 Callable,Future,FutureTask
  
    Callable接口与Runnable接口类似,封装了一个异步运行的任务,但与run方法不同,它的call方法可以有一个返回值并且可以抛出异常。Callable接口是个参数化的类型 public interface Callable{ V call() throws Exception} ,类型参数就是返回值的类型。

    Future接口用于表示异步计算的结果,并提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future 形式类型、并返回 null 作为底层任务的结果。下面是JDK给的例子:
 interface ArchiveSearcher { String search(String target); }
 class App {
   ExecutorService executor = ...
   ArchiveSearcher searcher = ...
   void showSearch(final String target)throws InterruptedException {
     Future future = executor.submit(new Callable() {
         public String call() {
             return searcher.search(target);
         }});
     displayOtherThings(); // do other things while searching
     try {
       displayText(future.get()); // use future
     } catch (ExecutionException ex) { cleanup(); return; }
   }
 } 
    FutureTask类代表可取消的异步计算,它采用包装器机制,可将Callable转换成Runnable和Future,它同时实现了这两个接口。下面是用法实例:

Callable myCallable = new MyCallable();
FutureTask task = new FutureTask(myCallable);
new Thread(task).start();
...
T result = task.get();

二、执行器

1.Executor接口与ThreadPoolExecutor

    Executor用于执行已提交的Runnable任务,它将任务的提交与每个任务如何运行的机制(包括线程使用的细节、调度等)分离开来。它仅提供了一个excecute方法。它有两个子接口:ExcecuteService和SheduledExecutorService

    ExecutorService提供了相关方法以管理终止,以及相关方法以跟踪一个或多个异步任务执行状况。可以关闭ExecutorService,shutdown方法被调用后将等待已提交的任务运行结束才会关闭服务,而shutdownNow方法将阻止任务启动并尝试停止正在运行的任务。被关闭的ExecutorService没有等待启动的任务,没有正在运行的任务,也无法向其提交新的任务。应该关闭不再使用的ExecutorService以回收资源。

    ThreadPoolExecutor线程池实现了ExecutorService接口。使用线程池可以避免频繁创建线程的开销,适合执行大量生命周期较短的任务。对于每个任务,如果线程池中有线程可用,则让它立即执行任务,否则创建一个新线程让其执行或者将其放入等待队列。

线程池的常见用法:
(1)调用Executors中的静态方法或者ThreadPoolExecutor构造方法创建线程池对象。
(2)调用submit提交Runnable或Callable对象,
(3)如果要取消一个任务,那就应该保存好返回的Future对象。
(4)当不再提交任何任务时,应该调用shutdown方法关闭线程池

2. 控制任务组

    ExecutorService执行器提供了许多控制任务执行的方法。

    shutdownNow方法可以取消所有正在执行的任务和未执行的任务。
    invokeAny方法将所有所有任务对象作为一个集合提交到执行器中,并返回一个Future列表。当这些任务中的任一个执行完毕后返回结果,无法知道返回的究竟是哪个任务的结果。此方法适合于多种方式并行处理一个问题的场景,只要求尽快得到结果,具体哪种方法起作用不关心。
    invokeAll与invokeAny不同,所有任务都会返回结果。但如果Future列表中第一个对应任务执行时间最长,则其他任务结果的获得不得不等待。可以使用ExecutorCompletionService来获取顺序返回的任务结果。

ExecutorCompletionService的用法:

ExecutorCompletionService service = new ExecutorCompletionService(executor);
for(Callable task : tasks)
  service.submit(task);
for(int i=0;i   processFurther(service.take().get());


   
阅读(1107) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~