巧用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锁的限制,性能上不存在问题。

经验分享 程序员 微信小程序 职场和发展