java CompletionService的理解和练习

业精于勤荒于嬉,写文章练习表达能力,写代码练习基本工。

练习目标:

掌握 Java 8 新增的CompletionService的优点,用法和使用场景。


练习题目:

执行1000个任务,顺序获取结果,为了体现CompletionService的优点,这里同时用ExecutorService作为对比。

代码 – 子任务

	//总共1000个任务
    private static final int MAX_NUM = 1000;

	//使用Callable,适用于需要返回值的场景。
    public static class MyCallable implements Callable<Integer>{
        int num;
        public MyCallable(int num) {
            this.num = num;
        }

        @Override
        public Integer call() throws Exception {
            Thread.sleep(3000);//保证测试公平性,统一耗时3秒。
//            System.out.println("第"+num+"个任务已完成!");
            return num;
        }
    }

代码 – ExecutorService普通线程池执行

    public static void testExecutorService() throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(MAX_NUM);

        try {

            List<Future> futureList = new ArrayList<>();

            long startTime = System.currentTimeMillis();

            for (int i = 0; i < MAX_NUM; i++) {
                futureList.add(executor.submit(new MyCallable(i)));
            }
            for (int i = 0; i < MAX_NUM; i++) {
                futureList.get(i).get();
//                System.out.println("第:"+(futureList.get(i).get()) +"个任务返回");
            }

            System.out.println("耗时:"+(System.currentTimeMillis() - startTime) +"毫秒");

        }finally {
            executor.shutdown();
            executor.awaitTermination(1,TimeUnit.MINUTES);
        }
    }

代码 – ExecutorCompletionService线程池执行

    public static void testCompletionService() throws InterruptedException, ExecutionException {

        ExecutorService executor = Executors.newFixedThreadPool(MAX_NUM);
        CompletionService completionService = new ExecutorCompletionService(executor);

        try {

            long startTime = System.currentTimeMillis();

            for (int i = 0; i < MAX_NUM; i++) {
                completionService.submit(new MyCallable(i));
            }

            for (int i = 0; i < MAX_NUM; i++) {
//                System.out.println("第:"+(completionService.take().get()) +"个任务返回");
                completionService.take().get();
            }

            System.out.println("耗时:"+(System.currentTimeMillis() - startTime) +"毫秒");

        }finally {
            executor.shutdown();
            executor.awaitTermination(1,TimeUnit.MINUTES);
        }

    }

代码 – main

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        testExecutorService();
        testCompletionService();
    }

耗时:3229毫秒
耗时:3056毫秒

结论

此场景下,使用ExecutorCompletionService会有优势

原因

  1. 子任务返回的furture,调用get后,如果子任务没有完成,会阻塞子任务直到结束,如果已经完成,直接返回结果。
  2. ExecutorCompletionService维护了一个队列,采用“先完成先入列”的思想,在调用take后,获取的都是已经结束的任务。
  3. 普通线程池在顺序调取furture的get方法获取结果时,遍历到的子任务可能没结束,会阻塞等待结果。
  4. ExecutorCompletionService在这一个场景,省去了3的时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值