今天再处理kafka日志消息时,按批次每次处理10000条,最后发现每批次处理结果都会比实际数量少一些,最后对代码进行跟踪发现问题,记录下。
我们都知道parallelStream使用的时ForkJobTask。而Fork/Join框架是通过把一个大的任务不断的fork成许多子任务,然后多线程执行这些子任务,最后再join这些子任务得到最终结果数据。
也就是说,如果你有一个大的数据集要处理,它会将你的数据集切分成若干个小的集合,处理之后再进行聚合,但是我的数据集是ArrayList类型,他的add方法不是线程安全的,不能保证原子性。
ArrayList的add方法源码如下:
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
可以看到add方法可以概括为以下两个步骤
- ensureCapacityInternal(),确认下当前ArrayList中的数组,是否还可以加入新的元素。如果不行,就会再申请一个:int newCapacity = oldCapacity + (old