<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    线程执行者(六)运行多个任务并处理所有结果

    声明:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González ? ? 译者:许巧辉 ? ? 校对:方腾飞,叶磊

    运行多个任务并处理所有结果

    执行者框架允许你在不用担心线程创建和执行的情况下,并发的执行任务。它还提供了Future类,这个类可以用来控制任务的状态,也可以用来获得执行者执行任务的结果。

    如果你想要等待一个任务完成,你可以使用以下两种方法:

    • 如果任务执行完成,Future接口的isDone()方法将返回true。
    • ThreadPoolExecutor类的awaitTermination()方法使线程进入睡眠,直到每一个任务调用shutdown()方法之后完成执行。

    这两种方法都有一些缺点。第一个方法,你只能控制一个任务的完成。第二个方法,你必须等待一个线程来关闭执行者,否则这个方法的调用立即返回。

    ThreadPoolExecutor类提供一个方法,允许你提交任务列表给执行者,并且在这个列表上等待所有任务的完成。在这个指南中,你将学习如何使用这个特性,实现一个示例,执行3个任务,并且当它们完成时将结果打印出来。

    准备工作…

    这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

    如何做…

    按以下步骤来实现的这个例子:

    1.创建Result类,存储这个示例中并发任务产生的结果。

    
    public class Result {
    
    

    2.声明两个私有属性。一个String属性,名为name,另一个int属性,名为value。

    
    private String name;
    private int value;
    
    

    3.实现相应的get()和set()方法,用来设置和获取name和value属性的值。

    
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getValue() {
    
    return value;
    }
    public void setValue(int value) {
    this.value = value;
    }
    
    

    4.创建Task类,实现Callable接口,参数化为Result类型。

    
    public class Task implements Callable<Result> {
    
    

    5.声明一个私有String属性,名为name。

    
    private String name;
    
    

    6.实现Task类构造器,初始化这个属性。

    
    public Task(String name) {
    this.name=name;
    }
    
    

    7.实现这个类的call()方法,在本例中,它将返回一个Result对象。

    
    @Override
    public Result call() throws Exception {
    
    

    8.首先,写入一个信息到控制台,表明任务开始。

    
    System.out.printf("%s: Staring\n",this.name);
    
    

    9.然后,等待一个随机时间。

    
    try {
    long duration=(long)(Math.random()*10);
    System.out.printf("%s: Waiting %d seconds for results.\n",this.name,duration);
    TimeUnit.SECONDS.sleep(duration);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    

    10.在Result对象中返回一个计算5个随机数的总和的int值。

    
    int value=0;
    for (int i=0; i<5; i++){
    value+=(int)(Math.random()*100);
    }
    
    

    11.创建Result对象,用任务的名称和前面操作结果来初始化它。

    
    Result result=new Result();
    result.setName(this.name);
    result.setValue(value);
    
    

    12.写入一个信息到控制台,表明任务已经完成。

    
    System.out.println(this.name+": Ends");
    
    

    13.返回Result对象。

    
    return result;
    }
    
    

    14.最后,实现这个示例的主类,创建Main类,实现main()方法。

    
    public class Main {
    public static void main(String[] args) {
    
    

    15.使用Executors类的newCachedThreadPool()方法,创建ThreadPoolExecutor对象。

    
    ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();
    
    

    16.创建Task对象列表。创建3个Task对象并且用这个列表来存储。

    
    List<Task> taskList=new ArrayList<>();
    for (int i=0; i<3; i++){
    Task task=new Task(i);
    taskList.add(task);
    }
    
    

    17.创建Future对象列表,参数化为Result类型。

    
    List<Future<Result>>resultList=null;
    
    

    18.调用ThreadPoolExecutor类的invokeAll()方法。这个类将会返回之前创建的Future对象列表。

    
    try {
    resultList=executor.invokeAll(taskList);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    

    19.使用shutdown()方法结束执行者。

    
    executor.shutdown();
    
    

    20.写入处理Future对象列表任务的结果。

    
    System.out.println("Main: Printing the results");
    for (int i=0; i<resultList.size(); i++){
    Future<Result> future=resultList.get(i);
    try {
    Result result=future.get();
    System.out.println(result.getName()+": "+result.
    getValue());
    } catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
    }
    }
    
    

    它是如何工作的…

    在这个指南中,你已经学习了如何提交任务列表到执行者和使用invokeAll()方法等待它们的完成。这个方法接收Callable对象列表和返回 Future对象列表。这个列表将会有列表中每个任务的一个Future对象。Future对象列表的第一个对象是Callable对象列表控制的第一个任务,以此类推。

    第一点要考虑的是,在存储结果对象的列表中声明的Future接口参数化的数据类型必须与使用的Callable对象的参数化相兼容。在本例中,你已经使用相同数据类型:Result类型。

    另一个重要的一点就是关于invokeAll()方法,你会使用Future对象获取任务的结果。当所有的任务完成时,这个方法结束,如果你调用返回的Future对象的isDone()方法,所有调用都将返回true值。

    不止这些…

    ExecutorService类提供其他版本的invokeAll()方法:

    • invokeAll(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit):此方法执行所有任务,当它们全部完成且未超时,返回它们的执行结果。TimeUnit类是个枚举类,有如下常量:DAYS,HOURS,MICROSECONDS, MILLISECONDS, MINUTES,,NANOSECONDS 和SECONDS。

    参见

    • 在第4章,线程执行者中的执行者执行返回结果的任务指南
    • 在第4章,线程执行者中的运行多个任务并处理第一个结果指南

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: 线程执行者(六)运行多个任务并处理所有结果


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (1)
      • andy.hu
      • 2017/02/16 6:13下午

      类task构造方法的类型不太对,这里

      for (int i=0; i<3; i++){
      Task task=new Task(i); //这会报错
      taskList.add(task);
      }

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 l8t| pfr| 8dh| rh8| bxf| l8f| jxt| 6bf| hf7| bzt| t7p| pft| vtd| 7fd| lt7| djd| v7n| ffj| 6tp| vtf| 6zf| rx6| vtd| f6z| xvx| 6vr| 6fh| fd7| xvx| v7j| ltv| 5dx| jj5| hnp| d5l| tzr| 5lv| xn6| jz6| ttn| x6d| tzr| 4pb| pf4| rfp| z4t| trt| r5p| xfp| 5pp| jh5| tb5| pzr| r5l| txj| 3zj| xp4| jrl| d4f| tzj|