问题描述
以下代码有时在ret.forEach(v -> System.out.println(v));
行生成NullPointerException异常。
我认为我必须使用同步块或锁定接口来避免此错误。
这是对的吗?
请告诉我一些建议。
List<Integer> ret = new ArrayList<>();
IntStream.range(0,10).parallel().forEach(i -> {
if (i % 2 == 0) {
try {
System.out.println("stop" + i);
Thread.sleep(10000);
} catch (InterruptedException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
}
ret.add(i);
});
ret.forEach(v -> System.out.println(v));
解决方法
基本上是:您从多个线程修改了ArrayList
。 ArrayList
并非线程安全的,因此这样做可能会导致任何数量的问题(不会一直出现单个问题/异常)。
不应该存在的空值是使用非线程集合的可能结果之一。
因此,从流中生成列表的最好方法是不使用forEach
并明确地向列表中添加内容,而是使用map
和collect
。
这里有些事情要评论:
-
ret
声明前不能使用。 -
您正在并行地将元素添加到
ArrayList
中。ArrayList
不是线程安全的,因此您不应该在那里使用它。看Choosing the best concurrency list in Java。 -
最后,如果您使用的是
streams
,最好使用map
和collect
。与此类似:IntStream.range(0,10) .parallel() .map(i -> do_watever(i)) .collect(Collectors.toList());;