web-dev-qa-db-ja.com

Java 8で並列ストリームから収集する

入力を取得し、その上に並列ストリームを適用したいので、リストとして出力します。入力は、ストリームを適用できるリストまたはコレクションです。

ここでの懸念は、マップとして出力したい場合、Javaは

_list.parallelStream().collect(Collectors.toConcurrentMap(args))
_

しかし、出力としてリストを提供するスレッドセーフな方法で並列ストリームから収集するオプションはありません。使用するオプションがもう1つあります

list.parallelStream().collect(Collectors.toCollection(<Concurrent Implementation>))

このようにして、collectメソッドでさまざまな同時実装を提供できます。ただし、Java.util.concurrentにはCopyOnWriteArrayList List実装のみが存在すると思います。ここではさまざまなキュー実装を使用できますが、それらはリストのようにはなりません。ここで私が意味するのは、リストを取得するための回避策があるということです。

リストとして出力したい場合の最良の方法は何ですか?

注:これに関連する他の投稿を見つけることができませんでした。参考資料があれば参考になります。

13
Vipul Goyal

収集されるデータの受信に使用されるCollectionオブジェクトは、同時である必要はありません。単純なArrayListを指定できます。

これは、パラレルストリームからの値のコレクションが実際に単一のCollectionオブジェクトに収集されないためです。各スレッドは独自のデータを収集し、すべてのサブ結果はマージされて単一の最終Collectionオブジェクトになります。

これはすべて Collector javadocで十分に文書化されており、Collectorcollect()に与えるパラメーターです。 メソッド:

<R,A> R collect(Collector<? super T,A,R> collector)
23
Andreas

But there is no option that I can see to collect from parallel stream in thread safe way to provide list as output。これはまったく間違っています。

ストリームのポイントは、スレッドセーフでないコレクションを使用して、完全に有効なスレッドセーフな結果を達成できることです。これは、ストリームがどのように実装されているかによるものです(これはストリームの設計の重要な部分でした)。 Collectorは、各ステップで新しいインスタンスを作成するメソッドsupplierを定義していることがわかります。それらのインスタンスはそれらの間でマージされます。

したがって、これは完全にスレッドセーフです。

 Stream.of(1,2,3,4).parallel()
          .collect(Collectors.toList());

このストリームには4つの要素があるため、ArrayListの4つのインスタンスが作成され、最後に1つの結果にマージされます(少なくとも4つのCPUコアを想定)

反対側でtoConcurrentのようなメソッドは単一の結果コンテナを生成し、すべてのスレッドは結果をそこに入れます。

6
Eugene