并发工具类:CompletionService有什么用?_使用场景

如何优化任务执行?

开发了一个比价网站,当用户查询某个商品的价格时,从S1和S2两个平台获取到对应的价格,保存在数据库中后,返回给用户

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<Integer> f1 = executor.submit(()-> getPriceByS1());
Future<Integer> f2 = executor.submit(()-> getPriceByS2());

Integer price1 = f1.get();
save(price1);

Integer price2 = f2.get();
save(price2);

如果获取电商S1报价的耗时很长,即使获取电商S2报价的耗时很短,也无法让保存S2报价的操作先执行,因为主线程都阻塞在f1.get()操作上了

解决方案一:

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<Integer> f1 = executor.submit(()-> getPriceByS1());
Future<Integer> f2 = executor.submit(()-> getPriceByS2());

BlockingQueue<Integer> bq = new LinkedBlockingQueue<>();
bq.put(f1.get());
bq.put(f2.get());

for (int i = 0; i < bq.size(); i++) {
Integer price = bq.take();
save(price);
}

解决方案二:

ExecutorService executor = Executors.newFixedThreadPool(2);
CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);

cs.submit(() -> getPriceByS1());
cs.submit(() -> getPriceByS2());

for (int i = 0; i < 2; i++) {
Integer price = cs.take().get();
save(price);
}

那么CompletionService如何实现这个功能的呢?

是不是也是通过把BlockingQueue和Executor组合一下来达到类似的功能的

CompletionService的使用场景

在CompletionService类的注释上其实标标明了CompletionService的2种使用场景

并发工具类:CompletionService有什么用?_解决方案_02


同时调用多个相同的服务获取结果,当有其中一个服务获取到结果后就返回,并取消其他任务。类似Dubbo的Forking Cluster

并发工具类:CompletionService有什么用?_解决方案_03

参考博客

[1]Java并发小册