2017-07-17 69 views
1

我正在使用流將字符串數組轉換爲hashmap。爲什麼paralel流可以提供不完整的元素列表

String[] arguments= new String[]{"-a","1","-b","2","-c","3","-d","4","-e","5"}; 
    HashMap<String, String> params = new HashMap<>(); 
    IntStream.iterate(0, i -> i + 2) 
      .limit(arguments.length/2) 
      .parallel() 
      .forEach(i -> params.put(arguments[i], arguments[i + 1])); 
    System.out.println(params.size()); 

這表明5,但有時4.

你能解釋一下,拜託,這可能是不同結果的原因是什麼?

+0

* *爲什麼「我使用的是流**轉換字符串數組的HashMap **」?使用普通的'for'循環。它更快,更簡單,更清晰,而且很有效! – Andreas

+0

第1步:學習解決沒有'forEach'的問題。第2步:認識到並行流並沒有爲這樣一個微不足道的任務付出代價(尤其是沒有並行不友好的'iterate(...).limit(...)'組合)。如果你想要一個有效的解決方案,你可以使用'HashMap params = IntStream.range(0,arguments.length/2).map(i - > i * 2).collect(HashMap :: new,( m,i) - > m.put(參數[i],參數[i + 1]),Map :: putAll);'這可以並行工作,但在並行處理中仍然沒有任何好處。 – Holger

回答

1

您正在打破基本流屬性 - 無副作用。並且您的信息流通過forEach有副作用。用簡單的話來說,你把來自多個線程的元素放到一個非線程安全的集合HashMap中。

做正確的方法,將收集通過:

String[] arguments = new String[] { "-a", "1", "-b", "2", "-c", "3", "-d", "4", "-e", "5" }; 
    Map<String, String> map = IntStream.iterate(0, i -> i + 2) 
      .limit(arguments.length/2) 
      .parallel() 
      .boxed() 
      .collect(Collectors.toMap(i -> arguments[i], i -> arguments[i + 1])); 

    System.out.println(map); // {-a=1, -b=2, -c=3, -d=4, -e=5} 
1

當使用並行流時,操作必須是無狀態否則由於線程調度的差異,您將得到非確定性結果。

這條線:

.forEach(i -> params.put(arguments[i], arguments[i + 1])); 

在每次執行的不同結果的原因。

解決您的問題的方法是利用collect還原操作並避免forEach

你可以找到更多信息有關無國籍行爲和副作用JAVA Stream API

相關問題