35

JDK 8 EA がリリースされました。ラムダと新しい 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はそれを述べていないのですか? 最後の質問ですが、ストリームの種類によって出力が異なる別の操作はありますか?

4

2 に答える 2

61

forEachOrderedではなく、を使用する必要がありますforEach

forEachドキュメントに従って:

並列ストリーム パイプラインの場合、この操作はストリームの検出順序を尊重することを保証しません。そうすると、並列処理の利点が犠牲になるからです。任意の要素に対して、いつでも、ライブラリが選択したスレッドでアクションを実行できます。アクションが共有状態にアクセスする場合、必要な同期を提供する責任があります。

于 2013-10-22T23:25:50.213 に答える
8

さらに、並列処理と forEachOrdered の詳細については、 here の非常に優れた例を参照してください。要約すると、並列ストリームで 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

5 番目のパイプラインは forEachOrdered メソッドを使用します。このメソッドは、ストリームをシリアルまたはパラレルで実行したかどうかに関係なく、ソースで指定された順序でストリームの要素を処理します。並列ストリームで forEachOrdered のような操作を使用すると、並列処理の利点が失われる可能性があることに注意してください

.

于 2015-02-25T14:05:06.423 に答える