2013-10-22 145 views
25

JDK 8 EA現在不在了,我只是想習慣lambda和新的Stream API。我試圖用排序並行流的列表,但結果始終是錯誤的:java 8 parallelStream()with sorted()

import java.util.ArrayList; 
import java.util.List; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     List<String> list = new ArrayList<>(); 
     list.add("C"); 
     list.add("H"); 
     list.add("A"); 
     list.add("A"); 
     list.add("B"); 
     list.add("F"); 
     list.add(""); 

     list.parallelStream() // in parallel, not just concurrently! 
      .filter(s -> !s.isEmpty()) // remove empty strings 
      .distinct() // remove duplicates 
      .sorted() // sort them 
      .forEach(s -> System.out.println(s)); // print each item 
    } 
} 

OUTPUT:

C 
F 
B 
H 
A 

注意,每次輸出是不同的。我的問題是,這是一個錯誤?還是不可能並行排序列表?如果是這樣,那爲什麼JavaDoc沒有聲明?最後一個問題,是否有另一個操作的輸出根據流類型而有所不同?

+1

排序後刪除重複可能會更好。 – Ingo

回答

44

您需要使用forEachOrdered而不是forEach

由於每forEach DOC:

對於並行流管道,此操作並不保證尊重流的相遇順序,因爲這樣做會犧牲並行的利益。對於任何給定的元素,該動作可以在任何時間和庫中選擇的任何線程中執行。如果操作訪問共享狀態,它負責提供所需的同步。

+1

+1燦爛!這是我正在尋找的。 –

+0

我的猜測是,它在內部創建一個「排序」列表,每個線程都添加到該列表中,然後繼續到流程中的下一步(forEach),以便它執行順序不正確,FWIW。 – rogerdpack

6

此外,您可以從here的一個很好的示例閱讀更多關於並行性和forEachOrdered。總之,在並行流中使用forEachOrdered可能會導致失去並行性的好處。

這裏由相同的資源的例子:

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 }; 
List<Integer> listOfIntegers = 
    new ArrayList<>(Arrays.asList(intArray)); 

System.out.println("listOfIntegers:"); 
listOfIntegers 
    .stream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("listOfIntegers sorted in reverse order:"); 
Comparator<Integer> normal = Integer::compare; 
Comparator<Integer> reversed = normal.reversed(); 
Collections.sort(listOfIntegers, reversed); 
listOfIntegers 
    .stream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("Parallel stream"); 
listOfIntegers 
    .parallelStream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("Another parallel stream:"); 
listOfIntegers 
    .parallelStream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("With forEachOrdered:"); 
listOfIntegers 
    .parallelStream() 
    .forEachOrdered(e -> System.out.print(e + " ")); 
System.out.println(""); 

並且輸出是

listOfIntegers: 
1 2 3 4 5 6 7 8 
listOfIntegers sorted in reverse order: 
8 7 6 5 4 3 2 1 
Parallel stream: 
3 4 1 6 2 5 7 8 
Another parallel stream: 
6 3 1 5 7 8 4 2 
With forEachOrdered: 
8 7 6 5 4 3 2 1 

第五管道使用方法forEachOrdered,其處理流的 元件在無論您是以串行還是並行方式執行流,它的源指定的順序爲 。 注意:如果使用 操作,如forEachOrdered平行流

,你可能會失去並行處理的益處。

+0

這有點薄。請通過編輯來擴展您的答案。 –