我有这段代码:
ArrayList<ArrayList<Double> results = new ArrayList<ArrayList<Double>();
IntStream.range(0, 100).parallel().forEach(x ->{
for (int y = 0; y <100;y++){
for (int z = 0; z <100;z++){
for (int q = 0; q <100;q++){
results.add(someMethodThatReturnsArrayListDouble);
}
}
}
});
System.out.println(results.size());
运行此代码后,我总是变得不同results.size()
,总是短暂的。知道为什么会这样,以及如何解决它?
答案 0 :(得分:1)
ArrayList
不是线程安全的。如果你尝试在不同的线程中添加项目(这是一个并行化的流),它可能会破坏。
来自docs:
请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作,或显式调整后备数组的大小;仅设置元素的值不是结构修改。)这通常通过同步一些自然封装的对象来实现。名单。如果不存在这样的对象,则该列表应该是&#34; wrap&#34;使用Collections.synchronizedList方法。
在这种情况下,最简单的解决方法是删除对parallel()
的调用。
答案 1 :(得分:1)
您的结果未同步。有多种方法可以解决您的问题,最好的方法是让java stream api处理列表的组合。
List<List<Double>> results = IntStream.range(0, 100).parallel().flatmap(x ->{
List<Double>> results = new ArrayList<Double>();
for (int y = 0; y <100;y++){
for (int z = 0; z <100;z++){
for (int q = 0; q <100;q++){
results.add(someMethodThatReturnsArrayListDouble);
}
}
}
return results.stream();
}).collect(Collectors.toList());
这会收集方法中的列表,并将它们作为流返回,并使用collectors.toList()在方法的末尾进行组合,这是什么是线程安全的。
答案 2 :(得分:0)
使用 Vector
它是List的线程安全实现。