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表達式的結果會在管道執行的過程中發生變化