public class ParallelStreamTest {
public static void test() {
List<Integer> listOfIntegers =
new ArrayList<>();
for (int i = 0; i < 10000; i++) {
listOfIntegers.add(i);
}
// 并发向List添加元素
List<User> parallelStorage = new ArrayList<>();
listOfIntegers
.parallelStream()
.forEach(i -> {
System.out.println(listOfIntegers.size());
System.out.println(i);
User user = new User();
parallelStorage.add(user);
});
parallelStorage.forEach(o -> {
System.out.println(o.getUsername());
});
}
public static void main(String[] args) {
test();
}
}
问题一:
List 并发添加元素出现null;
原因分析:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
执行add方法时,会先将此容器的大小增加。。即size++,然后将传进的元素赋值给新增的elementData[size++],即新的内存空间,但是此时如果在size++后直接来取这个List,而没有让add完成赋值操作,则会导致此List的长度加一,,但是最后一个元素是空(null),所以在获取它进行计算的时候报了空指针异常。
问题二:
原因分析:
当集合动态数组容量是10,集合已经添加了9个元素,一个线程率先进入add()方法,在执行ensureCapacityInternal(size + 1)时,发现还可以添加一个元素,故数组没有扩容,但随后该线程被阻塞在此处。接着另一线程进入add()方法,执行ensureCapacityInternal(size + 1),由于前一个线程并没有添加元素,故size依然为9,依然不需要扩容,所以该线程就开始添加元素,使得size++,变为10,数组已经满了。而刚刚阻塞在elementData[size++] = e;语句之前的线程开始执行,它要在集合中添加第11个元素,而数组容量只有10个,所以就发生了数组下标越界异常!
解决方法:
public class ParallelStreamTest {
public static void test() {
List<Integer> listOfIntegers =
new ArrayList<>();
for (int i = 0; i < 10000; i++) {
listOfIntegers.add(i);
}
// 并发向List添加元素
List<User> parallelStorage = listOfIntegers.parallelStream().filter(i -> i % 100 == 0).map(o -> {
User user = new User();
return user;
}).collect(Collectors.toList());
parallelStorage.forEach(o -> {
System.out.println(o.getUsername());
});
System.out.println(parallelStorage.size());
}
public static void main(String[] args) {
test();
}
}