java 8 parallel Stream()with sorted()

时间:2013-10-22 23:14:39

标签: java lambda parallel-processing java-8 java-stream

JDK 8 EA现在已经出局了,我只是想习惯lambda和新的Stream API。我试图用并行流对列表进行排序,但结果总是错误的:

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
    }
}

输出:

C
F
B
H
A

请注意,每次输出都不同。我的问题是,这是一个错误吗?或者不可能并行排序列表?如果是这样,那么JavaDoc为什么不说明这一点呢?最后一个问题,还有另一个操作,其输出会根据流类型而有所不同吗?

2 个答案:

答案 0 :(得分:51)

您需要使用forEachOrdered,而不是forEach

根据forEach doc:

  

对于并行流管道,此操作不保证遵守流的遭遇顺序,因为这样做会牺牲并行性的好处。对于任何给定元素,可以在任何时间以及库选择的任何线程中执行该动作。如果操作访问共享状态,则它负责提供所需的同步。

答案 1 :(得分:6)

此外,您可以通过here中的一个非常好的示例来阅读有关parallelism和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一样的操作