18

BlockingQueueのドキュメントによると、一括操作はスレッドセーフではありませんが、drainTo() メソッドについては明示的に言及されていません。

BlockingQueue の実装はスレッドセーフです。すべてのキューイング メソッドは、内部ロックまたはその他の形式の同時実行制御を使用して、アトミックに効果を達成します。ただし、一括コレクション操作の addAll、containsAll、retainAll、および removeAll は、実装で特に指定されていない限り、必ずしもアトミックに実行されるとは限りません。そのため、たとえば、c の一部の要素のみを追加した後、addAll(c) が失敗する (例外がスローされる) 可能性があります。

drainTo() メソッドのドキュメントでは、BlockingQueue の要素が排出されるコレクションは、スレッドセーフな方法で変更できないことが指定されています。しかし、drainTo() 操作がスレッドセーフであることについては何も言及されていません。

このキューから使用可能なすべての要素を削除し、指定されたコレクションに追加します。この操作は、このキューを繰り返しポーリングするよりも効率的です。コレクション c に要素を追加しようとして失敗した場合、関連付けられた例外がスローされたときに、要素がどちらのコレクションにも含まれないか、いずれかのコレクションに含まれないか、または両方のコレクションに含まれない可能性があります。キューをそれ自体にドレインしようとすると、IllegalArgumentException が発生します。さらに、操作の進行中に指定されたコレクションが変更された場合、この操作の動作は未定義です。

では、drainTo() メソッドはスレッドセーフですか? 言い換えると、あるスレッドがブロッキング キューで drainTo() メソッドを呼び出し、別のスレッドが同じキューで add() または put() を呼び出している場合、両方の操作の終了時にキューの状態は一貫していますか?

4

3 に答える 3

18

「スレッドセーフ」と「アトミック」という用語を混同していると思います。同じ意味ではありません。メソッドは、アトミックでなくてもスレッド セーフにすることも、スレッド セーフでなくてもアトミック (シングル スレッドの場合) にすることもできます。

スレッドセーフは、循環的でないと定義するのが難しいゴムのような用語です。Goetz 氏によると、メソッドがシングルスレッド コンテキストで実行される場合と同じようにマルチスレッド コンテキストで使用された場合に、そのメソッドがスレッド セーフであるというのが適切な作業モデルです。弾力性は、測定する正式な仕様がない限り、正確さが主観的であるという事実にあります。

対照的に、atomic は簡単に定義できます。これは単に、操作が完全に行われるか、まったく行われないことを意味します。

したがって、あなたの質問に対する答えは、drainTo()スレッドセーフですが、アトミックではありません。ドレインの途中で例外をスローする可能性があるため、アトミックではありません。ただし、他のスレッドが同時にキューに対して何かを行っていたかどうかにかかわらず、キューは一貫した状態のままです。


(上記の議論では、インターフェイスの特定の実装がインターフェイスを正しく実装していることは暗示されてBlockingQueueいます。そうでない場合、すべての賭けはオフです。)

于 2011-07-07T07:35:28.050 に答える
6

drainTo()同時に発生するキューでの操作は結果を変更せず、キューの状態を破壊しないという意味で、スレッドセーフです。そうでなければ、この方法はまったく無意味です。

ターゲット コレクション (結果が追加されるコレクション) が何か「賢い」ことを行うと、問題が発生する可能性があります。しかし、通常、単一のスレッドのみがアクセスできるコレクションにキューを排出するため、これは理論的な問題です。

于 2011-07-07T08:10:13.410 に答える