web-dev-qa-db-ja.com

SynchronousQueueを使用するタイミング

new SynchronousQueue()
new LinkedBlockingQueue(1)

違いはなんですか?容量が1のSynchronousQueueに対してLinkedBlockingQueueを使用する必要がある場合

50
Anton

synchronousQueueはハンドオフのようなものですが、LinkedBlockingQueueは単一の要素のみを許可します。違いは、synchronousQueueへのput()呼び出し返されない対応するtake()呼び出しがあるが、サイズ1のLinkedBlockingQueue、put()呼び出し(空のキューへ) )はすぐに戻ります。

私は自分でSynchronousQueueを直接使用したことがあるとは言えませんが、Executors.newCachedThreadPool()メソッドに使用されるデフォルトのBlockingQueueです。本質的には、実際にキューが必要ない場合(保留中のデータを保持したくない場合)のBlockingQueue実装です。

48
jtahlborn

上記のコードを理解する限り、同じことを行います。

いいえ、コードはまったく同じではありません。

同期Q申し出を成功させるにはウェイターが必要です。 LBQはアイテムを保持し、ウェイターがいなくてもオファーはすぐに終了します。

SyncQは、タスクのハンドオフに役立ちます。保留中のタスクとキューで待機している3つのスレッドを含むリストがあるとします。リストの1/4でoffer()を試してください。受け入れられない場合、スレッドはタスクを単独で実行できます。 [最後の1/4は現在のスレッドで処理する必要があります。なぜ1/3ではなく1/4なのか疑問に思う場合]

タスクをワーカーに渡そうと考えてください。何も使用できない場合は、自分でタスクを実行する(または例外をスローする)オプションがあります。反対に、LBQを使用すると、タスクをキューに残しても実行が保証されません。

注:コンシューマとパブリッシャーの場合は同じです。つまり、パブリッシャーはコンシューマーをブロックして待機しますが、offerまたはpollが戻った後、タスク/要素が処理されることを保証します。

9
bestsss

SynchronousQueueを使用する1つの理由は、アプリケーションのパフォーマンスを向上させることです。スレッド間でハンドオフが必要な場合は、同期オブジェクトが必要になります。その使用に必要な条件を満たすことができる場合、SynchronousQueueは私が見つけた最速の同期オブジェクトです。他の人も同意します。参照: BlockingQueueの実装:SynchronousQueueとLinkedBlockingQueueの違いは何ですか

6
snadata

[それを(おそらく)より明確な言葉にしようとしています。]

SynchronousQueue AP​​I docs は非常に明確に述べていると思います:

  1. 各挿入操作が別のスレッドによる対応する削除操作を待機する必要のあるブロッキングキュー、およびその逆。
  2. 同期キューには内部容量がなく、容量が1でもありません。要素は削除しようとしたときにのみ存在するため、同期キューを覗くことはできません。別のスレッドが要素を削除しようとしていない限り、(メソッドを使用して)要素を挿入することはできません。反復するものがないため、反復することはできません。
  3. キューの先頭は、最初にキューに入れられた挿入スレッドがキューに追加しようとしている要素です。そのようなキュースレッドが存在しない場合、削除可能な要素はなく、poll()nullを返します。

そして BlockingQueue AP​​Iドキュメント

  1. 要素を取得するときにキューが空にならないように待機し、要素を格納するときにキュー内のスペースが使用可能になるまで待機する操作を追加でサポートするキュー。

そのため、特に以下の3番目の点で、違いは明白であり、やや批判的に微妙です。

  1. BlockingQueueから取得するときにキューが空の場合、操作は新しい要素が挿入されるまでブロックされます。また、BlockingQueueに挿入するときにキューがいっぱいの場合、要素がキューから削除され、新しいキュー用のスペースが作成されるまで、操作はブロックされます。ただし、SynchronousQueueでは、反対の操作(挿入と削除は互いに反対)が別のスレッドで発生するため、操作がブロックされるため注意してください。 したがって、BlockingQueueとは異なり、ブロックは要素の存在または非存在の代わりに、操作の存在に依存します
  2. ブロックは反対の操作の存在に依存するため、要素は実際にはキューに挿入されません。そのため、2番目のポイント:「同期キューには内部容量がなく、容量が1でもありません。
  3. 結果として、peek()は常にnullを返し(再び、 API doc を確認します)、iterator()hasNext()は常にfalseを返します。 ( APIドキュメント )。ただし、poll()メソッドは、このキューの先頭をきちんと取得して削除します。別のスレッドが現在要素を使用可能にしており、そのようなスレッドが存在しない場合は、nullを返します。 ( APIドキュメント

最後に、SynchronousQueueクラスとLinkedBlockingQueueクラスの両方がBlockingQueueインターフェースを実装します。

1
anir

SynchronousQueueは同様の方法で動作しますが、次の大きな違いがあります。1)SynchronousQueueのサイズは0です。2)put()メソッドは、take()メソッドがキューからその要素を同時に取得できる場合にのみ要素を挿入します。コンシューマーのtake()コールが消費するのに時間がかかる場合、エレメントを挿入できません。

SynchronousQueue-その瞬間に誰かがそれを受信する場合にのみ挿入します。

0
Deepa Bhatia