public static void main(String[] args) throws InterruptedException
{
Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8};
List<Integer> listOfIntegers =
new ArrayList<>(Arrays.asList(intArray));
List<Integer> parallelStorage = new ArrayList<>();//Collections.synchronizedList(new ArrayList<>());
listOfIntegers
.parallelStream()
// Don't do this! It uses a stateful lambda expression.
.map(e -> {
parallelStorage.add(e);
return e;
})
.forEachOrdered(e -> System.out.print(e + " "));
System.out.println();
parallelStorage
.stream()
.forEachOrdered(e -> System.out.print(e + " "));
System.out.println();
System.out.println("Sleep 5 sec");
TimeUnit.SECONDS.sleep(5);
parallelStorage
.stream()
.forEachOrdered(e -> System.out.print(e + " "));
}
运行以上代码你可能会得到以下几种结果:
Result 1:
1 2 3 4 5 6 7 8
null 3 8 7 1 4 5 6
Sleep 5 sec
null 3 8 7 1 4 5 6
Result 2:
1 2 3 4 5 6 7 8
6 2 4 1 5 7 8
Sleep 5 sec
6 2 4 1 5 7 8
两个问题:
1.为什么parallelStorage的大小不固定?
2.为什么parallelStorage会有null元素?
最初我以为是因为主线程执行完成后并行流中的线程并未结束,sleep了主线程后发现结果并没有发生改变,其实我们可以认为ArrayList内部维护了一个数组Arr其定义一个变量 n用以表式这个数组的大小那么向这个ArrayList中存储数据的过程可以分解为这么几步:
1.读取数组的长度存入n
2.向这个数组中储入元素arr[n]=a
3.将n+1
4.保存n
A.对于元素中有null值的情况:
考虑三个线程的关系
如果是这种情况就会出现null元素;
B.而对于parrallelStorage元素数量不固定的原因就是多线程有可能同时读取到相同的下标n同时赋值,这样就会出现元素缺失的问题了
如何解决这个问题呢?我们可以将其转化为一个同步集合也就是
Collections.synchronizedList(new ArrayList<>())
但是要注意的是,在使用并行流的时候是无法保证元素的顺序的,也就是即使你用了同步集合也只能保证元素都正确但无法保证其中的顺序,这个在Oracle官方文档也有说明,不要使用有副作用的lambda表达式,那么什么是有副作用的lambda表达式呢?
官方文档说“ A stateful lambda expression is one whose result depends on any state that might change during the execution of a pipeline.”就是说这种lambda表达式的结果会在管道执行的过程中发生变化