CompletionService小记

风流意气都作罢 提交于 2020-03-01 04:06:18

CompletionService小记

在使用ExecutorService时,通过sumit执行一个Callable的时候,会立即返回一个异步任务结果,然后通过get获取异步任务结果的时候会阻塞,如下面这种情况,代码如下,

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Created by xinxingegeya on 16/3/22.
 */
public class ExecutorServiceTest {

    public static void main(String args[])
            throws ExecutionException, InterruptedException {

        ExecutorService executor = Executors.newCachedThreadPool();

        List<Future<Integer>> futureList = new ArrayList<>();
        for (int i = 5; i > 0; i--) {
            final int taskID = i;
            //CompletionService.submit()
            Future<Integer> res = executor.submit(new Callable<Integer>() {
                public Integer call() throws Exception {
                    Thread.sleep(taskID * 1000);
                    return taskID;
                }
            });
            futureList.add(res);
        }

        for (Future<Integer> future : futureList) {
            int result = future.get();
            System.out.println(result);
        }

        executor.shutdown();

        while (executor.isTerminated()) {
            executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
        }
    }
}

通过代码可以看到,在遍历任务结果集的时候,获取第一个任务结果,然后get会阻塞,会阻塞大概五秒的时间,而对于后面的任务,可能已经执行完成了,但就是阻塞在了第一Future上,这是不合理的,那么如何改进,在这里应该要使用CompletionService,如下代码,

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by xinxingegeya on 16/3/22.
 */
public class ExecutorCompletionServiceTest {

    public static void main(String args[]) throws InterruptedException {

        ExecutorService executor = Executors.newCachedThreadPool();

        CompletionService<Integer> cs = new ExecutorCompletionService<>(
            executor);
        for (int i = 5; i > 0; i--) {
            final int taskID = i;
            //CompletionService.submit()
            cs.submit(new Callable<Integer>() {
                public Integer call() throws Exception {
                    Thread.sleep(taskID * 1000);
                    return taskID;
                }
            });
        }
        // 可能做一些事情
        for (int i = 1; i < 5; i++) {
            try {
                int result = cs.take().get();//CompletionService.take()返回Future
                System.out.println(result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

        executor.shutdown();

        while (executor.isTerminated()) {
            executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
        }

        System.out.println("done");
    }
}

使用CompletionService的好处就是优先获取已经执行完成的任务结果,而不会一味的等待还没有执行完成的任务。

CompletionService的实现机制就是利用BlockingQueue,如果任务已经执行完成,会把Future放进阻塞队列里面,如果阻塞队列中有已经完成的任务,那么就取出来(take)获取异步任务的结果。

==============END==============

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!