BlockingQueue のdrainTo() メソッドのスレッドセーフ性 質問する

BlockingQueue のdrainTo() メソッドのスレッドセーフ性 質問する

の文書化ブロッキングキュー一括操作はスレッドセーフではないと書かれていますが、drainTo() メソッドについては明示的に言及されていません。

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

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

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

では、drainTo() メソッドはスレッドセーフでしょうか? つまり、1 つのスレッドがブロッキング キューで dumpTo() メソッドを呼び出し、他のスレッドが同じキューで add() または put() を呼び出している場合、両方の操作の終了時にキューの状態は一貫しているでしょうか?

ベストアンサー1

「スレッドセーフ」と「アトミック」という用語を混同していると思います。これらは同じ意味ではありません。メソッドは、アトミックでなくてもスレッドセーフになる可能性があり、スレッドセーフでなくてもアトミック (単一スレッドの場合) になる可能性もあります。

スレッドセーフとは、回りくどい表現にならないように定義するのが難しい、曖昧な用語です。Goetz 氏によると、適切な動作モデルは、メソッドがマルチスレッド コンテキストで使用されても、シングル スレッド コンテキストで実行された場合と「同じくらい正確」である場合に、そのメソッドはスレッドセーフであるということです。曖昧なのは、比較対象となる正式な仕様がない限り、正確さが主観的であるという事実です。

対照的に、アトミックは定義が簡単です。これは、操作が完全に実行されるか、まったく実行されないかのどちらかを意味します。

したがって、質問に対する答えは、drainTo()スレッドセーフではあるがアトミックではない、ということです。排出の途中で例外をスローする可能性があるため、アトミックではありません。ただし、それを除けば、他のスレッドが同時にキューに対して処理を行っていたかどうかに関係なく、キューは一貫した状態のままになります。


(上記の説明では、BlockingQueueインターフェースの特定の実装がインターフェースを正しく実装していることが暗黙的に示されています。そうでない場合は、すべてが台無しになります。)

おすすめ記事