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

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`CompletableFuture`是Java 8中引入的一个并发库组件,用于异步编程和处理未来的结果。它提供了一种线程安全、非阻塞的方式来执行计算任务,并在结果可用时返回。`CompletableFuture`的主要作用是在多个步骤的异步操作完成后获取最终结果。 当你创建一个`CompletableFuture`实例并开始执行一个任务,你可以使用以下几个方法来获取返回值: 1. `thenApply`: 当前`CompletableFuture`完成且成功时,应用给定的函数到结果上并返回一个新的`CompletableFuture`。 2. `thenCompose`: 类似于`thenApply`,但接受一个Function来转换完成的结果并返回新的`CompletableFuture`。 3. `get`: 如果当前任务已完成,将阻塞并立即返回结果。如果任务还在执行,会一直阻塞直到完成。这是一个阻塞操作,可能会抛出`InterruptedException`或`ExecutionException`。 4. `join`: 同样是阻塞操作,等待当前`CompletableFuture`完成,然后返回结果。 5. `get(long timeout, TimeUnit unit)`: 非阻塞地获取结果,如果在给定时间内任务未完成,抛出异常。 获取返回值的关键在于理解何时以及如何使用这些方法,以便正确处理可能的异步行为和错误。如果你有具体的代码示例,我可以帮助你分析其工作原理。相关问题: 1. CompletableFuture的基本用法是什么? 2. 如何处理`CompletableFuture`的异常情况? 3. 在并发编程中,为什么要避免在主线程中直接调用`get`方法?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值