巧用CompletableFuture返回值解决性能瓶颈
需求背景
对一组字符串数据进行处理,处理逻辑简单封装一个对象,包装该字符串,最终汇总返回。 下面实现只使用CompleteableFuture,其它方式如paraStream不考虑。
无返回值CompletableFuture实现
考虑到性能,对于字符串的处理可以进行并发。实现如下:
private static ExecutorService executorService = Executors.newFixedThreadPool(10, UserThreadFactory.build("future-test")); private List<String> result = new ArrayList<>(); @Before public void init() { for (int i = 0; i < 1000; i++) { result.add("a" + i); } } @Test public void testCompleteFuture1(){ List<List<String>> partition = Lists.partition(result, 100); Vector<AD> vector=new Vector<>(); List<CompletableFuture<Void>> futures = partition.stream().map(list -> { return CompletableFuture.runAsync(() -> { for (String s : list) { AD ad = new AD(); ad.name = s + "--p"; vector.add(ad); } }, executorService); }).collect(toList()); CompletableFuture.allOf(futures.toArray(new CompletableFuture[]{ })).join(); }
利用了CompletableFuture<Void>进行并发处理,使用线程安全的vector用于汇聚最后的数据。上文的存在的问题是线程安全的vector有锁导致性能降低,实现应用中逻辑比上述例子复杂,该处成为了性能瓶颈。
有返回值CompletableFuture实现
使用带有返回值的completable编码实现
public void testCompleteFuture2() { List<List<String>> partition = Lists.partition(result, 100); List<CompletableFuture<List<AD>>> futures = partition.stream().map(list -> { return CompletableFuture.supplyAsync(() -> { List<AD> ads = new ArrayList<>(); for (String s : list) { AD ad = new AD(); ad.name = s + "--p"; ads.add(ad); } return ads; }, executorService); }).collect(toList()); List<AD> collect = futures.stream().map(p -> { try { return p.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return null; }).filter(Objects::nonNull).flatMap(List::stream).collect(toList()); }
上述的例子则没了vector锁的限制,性能上不存在问题。
上一篇:
通过多线程提高代码的执行效率例子
下一篇:
Tomcat 安装并发布web应用