前段时间改造链路,发现链路上可能会出现丢掉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