2015-09-29 10 views
6

非並行データ構造ソースのストリームを使用するための非干渉要件は、実行中にデータ構造の要素の状態を変更できないことを意味しますか?ストリームパイプライン(ソースデータ構造自体を変更することはできません) (質問1)セクションでJava 8ストリームでの非干渉の正確な意味

non-interferenceは、ストリームパッケージの説明では、その言った: 「ほとんどのデータ・ソースの場合、干渉を防止することは、データソースがの実行中に全てで修飾されていないことを確実にする手段ストリームパイプライン。

この節では要素の状態の変更については言及していませんか?

たとえば、「シェイプ」がスレッドセーフではないコレクション(ArrayListなど)であると仮定すると、以下のコードで干渉が発生していると考えられますか?それは正確でなければならないので(質問2)

shapes.stream() 
     .filter(s -> s.getColor() == BLUE) 
     .forEach(s -> s.setColor(RED)); 

この例は、(控えめに言って)reliable sourceから取られます。 しかし、stream()parallelStream()に変更した場合でも、それはまだ安全で正しいでしょうか? (質問3)

もう一方の信頼できる情報源であるNaftalin Mauriceの "Mastering Lambdas"は、パイプライン操作によって要素の状態(値)を変更することが実際には干渉であることを明確にしています。非干渉(3.2.3)に関するセクションから:

"ストリームのルールは、パイプライン操作だけでなく、どのスレッドでも要素の値を変更するなど、ストリームソースの変更を禁止しています"

本書の内容が正しい場合は、ストリームAPIを使用して要素の状態を変更することはできません(forEachを使用)。通常のイテレータを使用するか、またはIterable.forEach)? (質問4)

答えて

6

"副作用のある関数"というより大きなクラスの関数があります。 JavaDocステートメントは正確で完全です。ここでの干渉とは、変更可能なソースを変更することを意味します。もう1つのケースは、ステートフルな式です:アプリケーションの状態に依存するか、この状態を変更する式。オラクルのサイトでParallelismチュートリアルを読むことができます。

一般に、ストリーム要素自体を変更することができ、「干渉」と呼ばれることはありません。ストリームソースによって複数回生成された同じ可変オブジェクトがある場合は注意してください(たとえば、Collections.nCopies(10, new MyMutableObject()).parallelStream()を使用します)。同じストリーム要素が複数のスレッドで同時に処理されないようにしていますが、ストリームが同じ要素を2回生成する場合、

ステートフルな表現は時に​​は匂いがしますが、ステートレスな代替方法がある場合は注意して使用して避けるべきですが、干渉しなければ大丈夫でしょう(例えば、Stream.mapメソッドで)ステートレス表現が必要な場合は、APIドキュメントに特別に記載されています。forEach文書では、非干渉のみが必要です。

だから、戻っご質問:

質問1:いいえ、私たちは、要素の状態を変更することができ、および(statefullnessと呼ばれるが)それは干渉と呼ばれていない

質問2:あなたがオブジェクトを繰り返していない限り、それは何の干渉を持っていません)あなたのストリームソースで

質問3:いいえ、あなたはこのような場合にはストリームAPIを使用することができます:あなたが安全にそこparallelStream()

質問4を使用することができます。

+1

つまり、「干渉」はより高いレベルにあります。ストリーム要素を変更するアクションは、同じ要素を同時に変更しているときに干渉しますが、別個のオブジェクトを変更しているときは干渉しません。同様に、 'ArrayList'自体はスレッドセーフではないが、' ArrayList'が同時のシナリオで正しく使用される可能性を排除するものではない。それはすべてについてです、*どのように使用されていますか? – Holger

+0

あなたの明確で詳細な答えをお送りいただきありがとうございます。コレクション内の変更可能な要素を維持することは一般的な作業であり、イテレータを使用して行われるコレクションの多くの操作は要素の状態を変更する必要があるため、実際には気になります。私たちが安全に行うことができなければ、ストリームを(少なくともパラレルストリームの場合は)あまり役に立たないでしょう。 – Shay

+0

Tagirステートフルラムダは、ストリームパッケージ(およびあなたが言及したリンク)で、結果がストリームパイプラインの実行中に変更される可能性のある状態に依存するものとして定義されていることに注意してください。 – Shay

1

データ構造に格納されたオブジェクトの状態を変更することは、データ構造の要素を再割り当てすることとは異なります。

もう1つは、「要素の値を変更する」と書くと、既存のListのインデックスに新しいオブジェクトを割り当てるかのように解釈されます。あなたのlinkから

それは方法をスト​​リームに渡されたラムダのいずれかの副作用を避けるのがベストです。値を出力するデバッグステートメントなどの副作用は通常安全ですが、ラムダが複数のスレッドから同時に実行される可能性があるため、これらのラムダからの可変状態にアクセスするとデータ競合や驚くべき動作が発生する可能性があります。注文。非干渉は、ソースに干渉しないだけでなく、他のラムダに干渉しないことを含む。このような干渉は、あるラムダが変更可能な状態を変更し、別のラムダが変更可能な状態を変更するときに生じる可能性があります。

非干渉要件が満たされている限り、ArrayListなどのスレッドセーフでないソースでも、並列操作を安全かつ予測可能な結果で実行できます。

これは、特に並列性に関係し、他の並行プログラミングと変わりはありません。状態を変更すると、スレッド間の可視性に問題が生じる可能性があります。

+0

Timさんにお返事いただきありがとうございます。具体的には、ストリームソースの要素の状態を変更することについての不確かさが感じられました。変更しない副作用が「値を出力するデバッグステートメント」として正当化されるためです。それは私の問題と直接対立しません。 – Shay

+1

私はあなたが並列操作をしており、より多くの操作を行う場合、ガイダンスは状態を変更しないと思います。 –

関連する問題