吐了 — 被ParallelStream坑惨

本文探讨了在Java中使用ParallelStream时遇到的问题,包括如何理解ParallelStream与ForkJoinPool的关系,以及如何避免丢掉ThreadLocal数据。文章强调了在使用ParallelStream时要注意线程安全,因为它可能导致阻塞,并非所有场景都适合使用。此外,还分析了默认的commonPool线程数设置,解释了为什么主线程也可能参与ParallelStream的任务执行。最后,提醒开发者深入理解常用技术的底层原理,避免踩坑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间改造链路,发现链路上可能会出现丢掉threadlocal中数据的情况,排查发现是在执行parallelStream后出现了丢标,并且这个丢标是偶发的。

附面试思维导图:

 

public static void main(String[] args) {
    List<Integer> lists = Lists.newArrayList();
    for (int i = 0; i < 4; i++) {
        lists.add(i);
    }
    //add threadLocal
    //something...
    //get threadLocal;
    lists.parallelStream().forEach(e -> {
        //set threadLocal;
        //do something
        //clear threadLocal;
    });
    //get threadLocal
}

多次执行后发现,parallelStream之后的标出现偶发性的被吞。(注:这里因为使用了部分集团内部组件,因此使用threadLocal替代)

[1]什么是ParallelStream

Stream(流)是JDK8中引入的一种类似与迭代器(Iterator)的单向迭代访问数据的工具。ParallelStream则是并行的流,它通过Fork/Join 框架(JSR166y)来拆分任务,加速流的处理过程。最开始接触parallelStream很容易把其当做一个普通的线程池使用,因此也出现了上面提到的开始的时候打标,结束的时候去掉标的动作。

ForkJoinPool又是什么

ForkJoinPool是在Java 7中引入了一种新的线程池,其简单类图如下:

可以看到ForkJoinPool是ExecutorService的实现类,是一种线程池。创建了ForkJoinPool实例之后,可以通过调用submit(ForkJoinTask task) 或invoke(ForkJoinTask task)方法来执行指定任务。 ForkJoinTask表示线程池中执行的任务,其有两个主要的抽象子类:RecusiveAction和RecusiveTask。其中RecusiveTask代表有返回值的任务,而RecusiveAction代表没有返回值的任务。它们的类图如下:

ForkJoinPool来支持使用分治法(Divide-and-Conquer Algorithm)来解决问题,即将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结果。相比于ThreadPoolE

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值