new SynchronousQueue()
new LinkedBlockingQueue(1)
違いはなんですか?容量が1のSynchronousQueue
に対してLinkedBlockingQueue
を使用する必要がある場合
synchronousQueueはハンドオフのようなものですが、LinkedBlockingQueueは単一の要素のみを許可します。違いは、synchronousQueueへのput()呼び出し返されない対応するtake()呼び出しがあるが、サイズ1のLinkedBlockingQueue、put()呼び出し(空のキューへ) )はすぐに戻ります。
私は自分でSynchronousQueueを直接使用したことがあるとは言えませんが、Executors.newCachedThreadPool()
メソッドに使用されるデフォルトのBlockingQueueです。本質的には、実際にキューが必要ない場合(保留中のデータを保持したくない場合)のBlockingQueue実装です。
上記のコードを理解する限り、同じことを行います。
いいえ、コードはまったく同じではありません。
同期Q申し出を成功させるにはウェイターが必要です。 LBQはアイテムを保持し、ウェイターがいなくてもオファーはすぐに終了します。
SyncQは、タスクのハンドオフに役立ちます。保留中のタスクとキューで待機している3つのスレッドを含むリストがあるとします。リストの1/4でoffer()
を試してください。受け入れられない場合、スレッドはタスクを単独で実行できます。 [最後の1/4は現在のスレッドで処理する必要があります。なぜ1/3ではなく1/4なのか疑問に思う場合]
タスクをワーカーに渡そうと考えてください。何も使用できない場合は、自分でタスクを実行する(または例外をスローする)オプションがあります。反対に、LBQを使用すると、タスクをキューに残しても実行が保証されません。
注:コンシューマとパブリッシャーの場合は同じです。つまり、パブリッシャーはコンシューマーをブロックして待機しますが、offer
またはpoll
が戻った後、タスク/要素が処理されることを保証します。
SynchronousQueueを使用する1つの理由は、アプリケーションのパフォーマンスを向上させることです。スレッド間でハンドオフが必要な場合は、同期オブジェクトが必要になります。その使用に必要な条件を満たすことができる場合、SynchronousQueueは私が見つけた最速の同期オブジェクトです。他の人も同意します。参照: BlockingQueueの実装:SynchronousQueueとLinkedBlockingQueueの違いは何ですか
[それを(おそらく)より明確な言葉にしようとしています。]
SynchronousQueue
API docs は非常に明確に述べていると思います:
- 各挿入操作が別のスレッドによる対応する削除操作を待機する必要のあるブロッキングキュー、およびその逆。
- 同期キューには内部容量がなく、容量が1でもありません。要素は削除しようとしたときにのみ存在するため、同期キューを覗くことはできません。別のスレッドが要素を削除しようとしていない限り、(メソッドを使用して)要素を挿入することはできません。反復するものがないため、反復することはできません。
- キューの先頭は、最初にキューに入れられた挿入スレッドがキューに追加しようとしている要素です。そのようなキュースレッドが存在しない場合、削除可能な要素はなく、
poll()
はnull
を返します。
そして BlockingQueue
APIドキュメント :
- 要素を取得するときにキューが空にならないように待機し、要素を格納するときにキュー内のスペースが使用可能になるまで待機する操作を追加でサポートするキュー。
そのため、特に以下の3番目の点で、違いは明白であり、やや批判的に微妙です。
BlockingQueue
から取得するときにキューが空の場合、操作は新しい要素が挿入されるまでブロックされます。また、BlockingQueue
に挿入するときにキューがいっぱいの場合、要素がキューから削除され、新しいキュー用のスペースが作成されるまで、操作はブロックされます。ただし、SynchronousQueue
では、反対の操作(挿入と削除は互いに反対)が別のスレッドで発生するため、操作がブロックされるため注意してください。 したがって、BlockingQueue
とは異なり、ブロックは要素の存在または非存在の代わりに、操作の存在に依存します。peek()
は常にnull
を返し(再び、 API doc を確認します)、iterator()
はhasNext()
は常にfalse
を返します。 ( APIドキュメント )。ただし、poll()
メソッドは、このキューの先頭をきちんと取得して削除します。別のスレッドが現在要素を使用可能にしており、そのようなスレッドが存在しない場合は、null
を返します。 ( APIドキュメント )最後に、SynchronousQueue
クラスとLinkedBlockingQueue
クラスの両方がBlockingQueue
インターフェースを実装します。
SynchronousQueueは同様の方法で動作しますが、次の大きな違いがあります。1)SynchronousQueueのサイズは0です。2)put()メソッドは、take()メソッドがキューからその要素を同時に取得できる場合にのみ要素を挿入します。コンシューマーのtake()コールが消費するのに時間がかかる場合、エレメントを挿入できません。
SynchronousQueue-その瞬間に誰かがそれを受信する場合にのみ挿入します。