使用ExecutorCompletionService,按照任务完成的顺序获取结果

文章对比了不借助ExecutorCompletionService的阻塞获取线程池异步任务结果与使用CompletionService的两种方式,指出前者会阻塞直到所有任务中最长耗时的任务完成,而后者则能逐个获取已完成的任务,不受单个任务影响。
摘要由CSDN通过智能技术生成

1、不使用ExecutorCompletionService获取线程池异步执行结果的实现方式
测试代码:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    //不使用ExecutorCompletionService交给线程池执行异步任务,并阻塞获取执行结果的实现
    ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("batchCreate-%d").build();
    ExecutorService exec = Executors.newFixedThreadPool(20, threadFactory);
    List<Future<String>> futureList = Lists.newArrayList();
    long currentTimeMillis = System.currentTimeMillis();
    for (int i = 1; i <= 10; i++) {
        int finalI = i;
        Future<String> future = exec.submit(() -> {
            Thread.sleep(1000L * (11 - finalI));
            return Thread.currentThread().getName() + " : " + finalI;
        });
        futureList.add(future);
    }

    for (Future<String> future : futureList) {
        String result = future.get();
        System.out.println("阻塞时长:" + (System.currentTimeMillis() - currentTimeMillis) + " result:" + result);
    }
    exec.shutdown();
    System.out.println("********************finished:" + (System.currentTimeMillis() - currentTimeMillis));
    System.out.println();
}

执行结果:
在这里插入图片描述
结果分析:
以上代码中提交的任务,模拟的是一种最坏的任务耗时情况,从10秒~1秒,从执行结果看,是阻塞了10秒,也就是阻塞到执行时间最长的任务执行完成后,才能拿到首次执行结果,即碰到某个耗时慢的任务后,会等到此任务执行完成后,才继续获取后续任务的执行结果;

2、使用ExecutorCompletionService获取执行结果的方式
1)使用 Future 接收结果的方式,得到的效果和 1中的效果一样
代码如下:

public static void main(String[] args) throws InterruptedException, ExecutionException {
    ThreadFactory threadFactory1 = new ThreadFactoryBuilder().setNameFormat("batchCreate22222-%d").build();
    ExecutorService exec2 = Executors.newFixedThreadPool(20, threadFactory1);
    CompletionService<String> completionService = new ExecutorCompletionService<>(exec2);
    long currentTimeMillis1 = System.currentTimeMillis();

    List<Future<String>> futureList = Lists.newArrayList();
    for (int i = 1; i <= 10; i++) {
        int finalI = i;
        Future<String> stringFuture = completionService.submit(() -> {
            Thread.sleep(1000L * (11 - finalI));
            return Thread.currentThread().getName() + " : " + finalI;
        });
        futureList.add(stringFuture);
    }

    for (Future<String> stringFuture : futureList) {
        String result = stringFuture.get();
        System.out.println("阻塞时长:" + (System.currentTimeMillis() - currentTimeMillis1) + " result:" + result);
    }

    exec2.shutdown();
    System.out.println("******************finished:" + (System.currentTimeMillis() - currentTimeMillis1));
}

执行结果:
在这里插入图片描述
2)使用 ExecutorCompletionService take的方式获取阻塞结果

public static void main(String[] args) throws InterruptedException, ExecutionException {
    ThreadFactory threadFactory1 = new ThreadFactoryBuilder().setNameFormat("batchCreate22222-%d").build();
    ExecutorService exec2 = Executors.newFixedThreadPool(20, threadFactory1);
    CompletionService<String> completionService = new ExecutorCompletionService<>(exec2);
    long currentTimeMillis1 = System.currentTimeMillis();

    for (int i = 1; i <= 10; i++) {
        int finalI = i;
        completionService.submit(() -> {
            Thread.sleep(1000L * (11-finalI));
            return Thread.currentThread().getName()+" : "+finalI;
        });
    }

    for (int i = 1; i <= 10; i++) {
        String result = completionService.take().get();
        System.out.println("阻塞时长:" + (System.currentTimeMillis() - currentTimeMillis1) + " result:" + result);
    }
    exec2.shutdown();
    System.out.println("******************finished:" + (System.currentTimeMillis() - currentTimeMillis1));
}

运行结果:
在这里插入图片描述
结果分析:
从运行结果看,获取阻塞结果时,并没有因为碰到执行最长的任务而一致阻塞,而是逐个取到了最先执行完成的任务;
原因:
ExecutorCompletionService 中添加了一个队列,来存放线程池已经完成的任务,take方法是从队列中获取已经完成的任务。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值