私は私の質問をから再構成すると思います
Simple QueueImplementationsの代わりにBlockingQueueImplementationsをどこで使用する必要がありますか?
に
速度、同時実行性、または最後の要素にアクセスする時間などのさまざまなその他のプロパティなどの側面を考慮した、キューの実装に対するBlockingQueueの長所/短所は何ですか?
私は両方の種類のキューを使用しました。ブロッキングキューは通常、並行アプリケーションで使用されることを知っています。 ByteBufferオブジェクトのプレースホルダーが必要な単純なByteBufferプールを作成していました。最速のスレッドセーフなキューの実装が必要でした。要素へのアクセス時間が一定であるArrayListのようなList実装もあります。
BlockingQueueとQueueとListの実装の長所と短所について誰かが話し合うことはできますか?
現在、これらのByteBufferオブジェクトを保持するためにArrayListを使用しています。
これらのオブジェクトを保持するためにどのデータ構造を使用しますか?
限られた容量のBlockingQueue
は、ある種のリクエストを抑制したい場合にも役立ちます。キューが無制限であるため、プロデューサーはコンシューマーよりもはるかに先を行くことができます。タスクは最終的に実行されますが(OutOfMemoryError
を引き起こすほど多くない限り)、プロデューサーは長い間あきらめている可能性があるため、労力が無駄になります。
このような状況では、キューがいっぱいであることをプロデューサー候補に通知し、失敗してすぐに諦める方がよい場合があります。たとえば、プロデューサーはWebリクエストであり、ユーザーが長く待ちたくない場合、待機中にCPUサイクルをあまり消費しませんが、ソケットやメモリなどの限られたリソースを消費しています。 。諦めると、すでにキューに入れられているタスクがタイムリーに終了する可能性が高くなります。
私が解釈している修正された質問について、「プールにオブジェクトを保持するための良いコレクションは何ですか?」
無制限 LinkedBlockingQueue
は、多くのプールに適しています。ただし、プール管理戦略によっては、 ConcurrentLinkedQueue
も機能する場合があります。
プーリングアプリケーションでは、ブロッキング「プット」は適切ではありません。キューの最大サイズの制御はプールマネージャーの仕事です。プールのリソースをいつ作成または破棄するかを決定します。プールのクライアントは、プールからリソースを借りて返します。新しいオブジェクトを追加するか、以前に借用したオブジェクトをプールに戻すことは、高速で非ブロッキング操作である必要があります。したがって、容量制限キューはプールには適していません。
一方、プールからオブジェクトを取得する場合、ほとんどのアプリケーションは、リソースが使用可能になるまで待機する必要があります。少なくとも一時的にブロックする「テイク」操作は、「ビジー待機」よりもはるかに効率的です。つまり、リソースが使用可能になるまで繰り返しポーリングします。この場合、LinkedBlockingQueue
が適切です。借り手は take
で無期限にブロックするか、 poll
でブロックする時間を制限することができます。
クライアントがまったくブロックする意思がないが、プールが空の場合にそれ自体のリソースを作成する機能がある場合は、あまり一般的ではありません。その場合、ConcurrentLinkedQueue
が適切な選択です。これは、リソース(メモリなど)をできるだけ共有するのがよい灰色の領域のようなものですが、速度はさらに重要です。最悪の場合、これはリソースの独自のインスタンスを持つすべてのスレッドに縮退します。そうすれば、スレッド間で共有しようとしないほうが効率的だったでしょう。
これらのコレクションは両方とも、並行アプリケーションで優れたパフォーマンスと使いやすさを提供します。非並行アプリケーションの場合、ArrayList
に勝るものはありません。動的に増加するコレクションの場合でも、LinkedList
の要素ごとのオーバーヘッドにより、いくつかの空のスロットを持つArrayList
は、メモリに関して競争力を維持できます。
マルチスレッドの状況では、BlockingQueue
が表示されます。たとえば、コンストラクターを使用して作成する場合は、作成するパラメーターとしてBlockingQueue
を渡す必要があります ThreadPoolExecutor
。エグゼキュータで渡すキューのタイプに応じて、動作が異なる場合があります。
これはQueue
実装であり、次の操作を追加でサポートします。
要素を取得するときにキューが空でなくなるのを待ち、
そして
要素を格納するときに、キューでスペースが使用可能になるのを待ちます。
上記の機能が必要な場合は、Queue
実装が続き、Blocking Queue
を使用します
BlockingQueue
は、相互に依存する並列操作をシリアル化する場合にも役立ちます。
具体的な(多少恣意的ではありますが)例を示すために、 ここ は、callInPatient()
をregisterPatientToAppointment()
と並行して起動する必要があるリアルタイムの患者キューWebアプリケーションの並列テストです。ただし、registerPatientToAppointment()
を実行する前に、callPatientInAtDoctorsOffice()
が完了するまで待機する必要があります。
public class ClinicPatientQueueAppTest extends ParallelTest {
private static final BlockingQueue WAIT_FOR_REGISTRATION_QUEUE = new ArrayBlockingQueue(2);
@Test
public void callInPatient() {
loginToDoctorsOffice("user", "password");
waitUntilRegistrationCompleted(); // <--
callPatientInAtDoctorsOffice();
}
@Test
public void registerPatientToAppointment() {
registerPatientAtRegistrationKiosk("Patient Peter");
notifyRegistrationCompleted(); // <--
}
private void waitUntilRegistrationCompleted() {
WAIT_FOR_REGISTRATION_QUEUE.take();
}
private void notifyRegistrationCompleted() {
WAIT_FOR_REGISTRATION_QUEUE.put(this);
}
}