2016-10-05 6 views
3

私はいくつかの記事を読みましたが、私はまだ混乱しています。Java 8ストリームはアトミックですか?

私は、パラレルストリームがCPUを利用する並列方法で実行されることを知っています。私はサブジョブが原子単位として実行されると信じていますが、正しいのですか?

しかし、通常のJava 8ストリームはどうですか?

私が実行した場合のコードの次の行を言わせて:

users.stream().map(user->user.getUsername()).collect(Collectors.toList()); 

は、その行も同様にスレッドセーフ/アトミックな方法で実行されますか?

+2

いいえ、サブジョブはアトミック単位として実行されませんが、それが意味するものは明確ではありません。シーケンシャルストリームは単一のスレッドで実行されるため、スレッドセーフである必要はありません。 –

+0

したがって、マルチスレッドシステムを使用していて、シーケンシャルストリームを使用していると、競合状態によってデータが不一致になることがありますか? –

+1

競合状態があるかどうかは、ストリーム処理とは関係ありません。私が言ったように、あなたが心に留めていることは非常に不明です –

答えて

1

一般的には、 Spliteratorが使用されていて、特性がCONCURRENTの場合、ストリームはスレッドセーフです。

2

一般的なスレッドの安全性やアトミック性はありません。原子フィールドの更新は、同じ変数にアクセスするスレッドに関しては原子レベルであり、コードブロックは同じインスタンス上でのみ同期するスレッドに関して原子単位/スレッド単位で安全に実行されます。

ストリーム操作自体は純粋にローカル操作です。この操作に参加するスレッドは他のスレッドとは無関係なので、これは並列ストリーム操作でも保持されます。非常に推奨されていない(ローカルではない)副作用を持つ関数を使用すると、これらの副作用に対してスレッドセーフやアトミック性は保証されません。唯一の例外は、端末操作forEachforEachOrderedです。これらは副作用を目的としており、複数のスレッドでの動作に関して十分に文書化されています。

したがって、getUsername()メソッドが契約に従い、副作用がないと仮定して、操作users.stream().map(user->user.getUsername()).collect(Collectors.toList())は、他のスレッドには全く表示されません。返されたリストをスレッドセーフな方法で他のスレッドに公開すると安全です。安全でない方法でエスケープすると、保証はありません。結果を他のスレッドに公開しないと、問題は無関係になります。

1

ストリームAPIは、パイプラインの各ステップごとに多数の契約を定義していますが、いずれかが違反すると予期しない動作や例外が発生する可能性があります。

  • Spliterator。レイトバインディング、IMMUTABLEおよびCONCURRENTプロパティーに注意してください。これはさまざまなソースで異なる場合があります。
  • コレクションソースは、通常、スプライテータの性質を指定します。 ConcurrentHashMapはビューに対してCONCURRENTを報告し、HashMapは報告しません。つまり、ハッシュマップはストリームパイプライン内の外部スレッドや干渉する副作用による変更を処理できません。
  • パイプライン内の各操作は、ユーザー提供のメソッドが持つべきプロパティを定義します。キーコンセプトは、non-interference、ステートフル性と副作用です。 filterpeekを比較してください。
  • Collector/Collectorsは、要件を明確にはっきりと説明していませんが、特にコンカレントコレクタを使用している場合には、通常、中間機能のように非干渉で、副作用がなく、ステートレスである必要があります。

一般的に、すべてを正しく行うと、並行した変更をサポートしていないコレクションであっても、パラレルストリームとシーケンシャルストリームの両方を安全に使用できます。

これらの要件に違反することを行っている場合、順次ストリームはもう少し寛容になるかもしれませんが、まだ失敗する可能性があります。

関連する問題