3.2 获得执行器任务的结果

获得执行器任务的结果

概述

创建线程的基本方法:实现Runnable接口没有方法能够返回线程执行结果。Executor Framework允许各并发任务返回结果。这个能力通过以下两个两个接口实现:
  • Callable:这个接口声明了call方法,在这个方法里实现任务的具体逻辑,并可以返回任务的结果。
  • Future:这个接口声明了一些方法来获取由Callabe对象产生的结果,并管理它们的状态。

示例

下面的示例演示了如何取得执行任务的结果:
public class CallableResultDemo {
    public static void main(String[] args){
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
        CallableReaultWorker worker = new CallableReaultWorker();

        //保存各个工作线程对应的Future对象
        List<Future<Long>> futures = new ArrayList<Future<Long>>(10);

        //创建工作任务线程,并提交给执行器。
        System.out.println("main:创建工作任务线程,并提交给执行器。");
        for(int i=0; i<5; i++){
            //注意:不能再使用execute方法,而是要使用submit方法,submit方法会返回这个任务对应的Future对象。
            Future<Long> future = executor.submit(worker);
            futures.add(future);
        }

        do{
            //查看各个执行器状态
            for(int i=0; i<futures.size(); i++){
                System.out.println("main:任务线程" + i + "是否执行完成:" + futures.get(i).isDone());
            }
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }while(executor.getActiveCount() > 0);

        //输出各个执行器结果
        for(int i=0; i<futures.size(); i++){
            try {
                System.out.println("main:任务线程" + i + "执行结果:" + futures.get(i).get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();
    }
}

class CallableReaultWorker implements Callable<Long>{
    @Override
    public Long call() throws Exception {
        long value = (long)(Math.random()*1000);
        System.out.println(Thread.currentThread().getName() + ":执行结果:" + value);
        Thread.sleep(value);

        return value;
    }
}

程序运行日志:

main:创建工作任务线程,并提交给执行器。
main:任务线程0是否执行完成:false
main:任务线程1是否执行完成:false
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:false
main:任务线程4是否执行完成:false
pool-1-thread-2:执行结果:614
pool-1-thread-1:执行结果:502
main:任务线程0是否执行完成:false
main:任务线程1是否执行完成:false
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:false
main:任务线程4是否执行完成:false
pool-1-thread-1:执行结果:444
main:任务线程0是否执行完成:true
main:任务线程1是否执行完成:false
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:false
main:任务线程4是否执行完成:false
pool-1-thread-2:执行结果:56
pool-1-thread-2:执行结果:821
main:任务线程0是否执行完成:true
main:任务线程1是否执行完成:true
main:任务线程2是否执行完成:false
main:任务线程3是否执行完成:true
main:任务线程4是否执行完成:false
main:任务线程0是否执行完成:true
main:任务线程1是否执行完成:true
main:任务线程2是否执行完成:true
main:任务线程3是否执行完成:true
main:任务线程4是否执行完成:false
main:任务线程0执行结果:502
main:任务线程1执行结果:614
main:任务线程2执行结果:444
main:任务线程3执行结果:56
main:任务线程4执行结果:821

关于获得全部结果

为了获得全部任务的执行结果必须等待全部任务执行完成,在上面的示例中是使用轮训等待的方式,如下:

do{
    //查看各个执行器状态
    for(int i=0; i<futures.size(); i++){
        System.out.println("main:任务线程" + i + "是否执行完成:" + futures.get(i).isDone());
    }
    try {
        Thread.sleep(300);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}while(executor.getActiveCount() > 0);

ThreadPoolExecutor类提供了一种更简单的方法来等待执行器执行完所有任务,那就是调用ThreadPoolExecutor类的invokeAll方法。调用方法可以提交一个任务列表给执行器,并等待列表中所有任务执行完成。用调用invokeAll方法的方式改写上面示例如下:

public class InvokeAllDemo {

    public static void main(String[] args){
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

        List<CallableReaultWorker> tasks = new ArrayList<CallableReaultWorker>();
        //保存各个工作线程对应的Future对象
        List<Future<Long>> futures = new ArrayList<Future<Long>>(10);

        //创建任务
        for(int i=0; i<10; i++){
            CallableReaultWorker worker = new CallableReaultWorker();
            tasks.add(worker);
        }


        //提交给执行器。
        System.out.println("main:提交给执行器,并等待任务执行完成。");
        try {
            futures = executor.invokeAll(tasks);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main:关闭执行器。");
        executor.shutdown();

        //输出各个执行器结果
        System.out.println("main:任务执行完成,输出任务结果。");
        for(int i=0; i<futures.size(); i++){
            try {
                System.out.println("main:任务线程" + i + "执行结果:" + futures.get(i).get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

程序执行日志:
main:提交给执行器,并等待任务执行完成。
pool-1-thread-2:执行结果:243
pool-1-thread-1:执行结果:295
pool-1-thread-2:执行结果:611
pool-1-thread-1:执行结果:364
pool-1-thread-1:执行结果:603
pool-1-thread-2:执行结果:268
pool-1-thread-2:执行结果:803
pool-1-thread-1:执行结果:974
pool-1-thread-2:执行结果:357
pool-1-thread-1:执行结果:449
main:关闭执行器。
main:任务执行完成,输出任务结果。
main:任务线程0执行结果:295
main:任务线程1执行结果:243
main:任务线程2执行结果:611
main:任务线程3执行结果:364
main:任务线程4执行结果:603
main:任务线程5执行结果:268
main:任务线程6执行结果:803
main:任务线程7执行结果:974
main:任务线程8执行结果:357
main:任务线程9执行结果:449




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值