ArrayBlockingQueueとLinkedBlockingQueueのソースコードを調べていました。LinkedBlockingQueueには、挿入と削除のためにそれぞれputLockとtakeLockがありますが、ArrayBlockingQueueは1つのロックのみを使用します。LinkedBlockingQueueは、シンプル、高速、実用的な非ブロッキングおよびブロッキング並行キューアルゴリズムで説明されている設計に基づいて実装されたと思います。このホワイトペーパーでは、デッドロックシナリオを回避するために、エンキューアがヘッドにアクセスする必要がなく、デキューアがテールにアクセスする必要がないように、ダミーノードを保持していると述べています。ArrayBlockingQueueが同じアイデアを借用せず、代わりに2つのロックを使用するのはなぜだろうと思っていました。
4 に答える
ArrayBlockingQueueは、エントリの上書きを回避する必要があるため、開始と終了がどこにあるかを知る必要があります。LinkedBlockQueueは、GCがキュー内のノードのクリーンアップについて心配することを可能にするため、これを知る必要はありません。
ArrayBlockingQueueが同じアイデアを借用せず、代わりに2つのロックを使用するのはなぜだろうと思っていました。
ArrayBlockingQueue
は、キュー項目を保持するためにはるかに単純なデータ構造を使用しているためです。
ArrayBlockingQueue
データを1つの配列に格納しますprivate final E[] items;
。複数のスレッドがこの同じストレージスペースを処理するには、追加またはデキューのいずれかで、同じロックを使用する必要があります。これは、メモリバリアだけでなく、同じアレイを変更しているためミューテックス保護が原因です。
LinkedBlockingQueue
一方、キュー要素のリンクリストは完全に異なり、デュアルロックを使用できます。さまざまなロック構成を有効にしたのは、キュー内の要素の内部ストレージです。
LBQでは2つのロックを使用して、ヘッドへのアクセスとロックを同時に制限します。ヘッドロックは2つの要素を同時に削除することを禁止し、テールロックは2つの要素を同時にキューに追加することを禁止します。2つのロックが一緒になってレースを防ぎます。
ABQがLBQと同じ考えを借りることは可能だと思います。私のコードhttp://pastebin.com/ZD1uFy7Sと、 SOArrayBlockingQueueで尋ねた同様の質問を参照してください。
彼らがそれを使用しなかった理由は、主に実装の複雑さ、特にイテレーターのためであり、複雑さとパフォーマンスの向上の間のトレードオフはそれほど儲かっていませんでした。
詳細については、http://jsr166-concurrency.10961.n7.nabble.com/ArrayBlockingQueue-concurrent-put-and-take-tc1306.htmlを参照してください。