CompletableFuture在性能优化中的使用

实践:打印一个集合内的所有内容

数据准备:

    private static final int COUNT = 100000;
    private Vector<String> datas;
    @Before
    public void init() {
        datas = new Vector<>();
        for (int i = 0; i < COUNT; i++) {
            datas.add("data-" + i);
        }
    }

ParallelStream

使用ParallelStream并行打印

    @Test
    public void testParallelStream(){
        datas.parallelStream().forEach(p->{
            System.out.println("p=" + p + "," + Thread.currentThread().getName());
        });
    }

打印结果

p=data-39215,ForkJoinPool.commonPool-worker-3
p=data-70897,main
p=data-70898,main
p=data-70899,main
p=data-70900,main
p=data-70901,main
p=data-70902,main
p=data-70903,main
p=data-70904,main
p=data-4288,ForkJoinPool.commonPool-worker-1
p=data-4289,ForkJoinPool.commonPool-worker-1

通过打印结果可以其使用了ForJoin的线程进行多线程打印逻辑,并且线程号递增至p=data-688,ForkJoinPool.commonPool-worker-7是由于测试机的CPU核心数就是8

Runtime.getRuntime().availableProcessors()

所以main+上7个ForkJoinPool.commonPool-worker等于CPU的核心数,验证了ParalleStream默认使用的是CPU核心数的线程池大小。

CompletableFutrue

使用CompletableFutrue则需要将数据集自行拆分,进行多线程的处理

    @Test
    public void testCompletableFuture() {
        ExecutorService nodeExecutor = new ThreadPoolExecutor(10, 100, 100L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), UserThreadFactory.build("discovery-l3-node"));
        List<List<String>> mePartition = Lists.partition(datas, 20);
        List<CompletableFuture<Void>> printFuture = mePartition.stream().map(ids -> CompletableFuture.runAsync(() -> {
            ids.forEach(p -> {
                System.out.println("p=" + p + "," + Thread.currentThread().getName());
            });
        }, nodeExecutor)).collect(Collectors.toList());
        CompletableFuture.allOf(printFuture.toArray(new CompletableFuture[]{})).join();
    }

代码中通过Lists.partition对集合进行了分组,然后利用核心线程数为10的线程进行数据的打印,结果如下:

p=data-196,discovery-l3-node-1-thread-10
p=data-197,discovery-l3-node-1-thread-10
p=data-198,discovery-l3-node-1-thread-10
p=data-199,discovery-l3-node-1-thread-10
p=data-200,discovery-l3-node-1-thread-1
p=data-201,discovery-l3-node-1-thread-1
p=data-202,discovery-l3-node-1-thread-1

对比

上述两种方式的特点很明显

  • ParallelStream编码方便
  • CompletableFuture灵活自定义线程,当然ParallelStream也可以使用自定义线程,此外CompletableFuture提供各类有时序的并发控制方法

注意事项

在多个CompletableFuture里如果一个线程安全的集合如vector操作,会导致多个CompletableFuture针对vector实际上是串行

ParallelStream自定义线程池

    @Test
    public void testParallelStream2() throws ExecutionException, InterruptedException {
        ForkJoinPool forkJoinPool = new ForkJoinPool(10);
        ForkJoinTask<?> submit = forkJoinPool.submit(() -> {
            datas.parallelStream().forEach(p -> {
                System.out.println("p=" + p + "," + Thread.currentThread().getName());
            });
        });
        submit.get();
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值