JavaDocsから:
2つのシナリオがあり、1つは1つのコンシューマーで多くのプロデューサー(それを使用するスレッド)をサポートするためにキューを必要とし、もう1つは他の方法です。
使用する実装がわかりません。誰かが違いを説明できますか?
また、ArrayBlockingQueue
の「オプションの公平性ポリシー」とは何ですか?
基本的に、それらの違いはパフォーマンス特性とブロック動作です。
最も簡単なものから順に、ArrayBlockingQueue
は固定サイズのキューです。したがって、サイズを10に設定して11番目の要素を挿入しようとすると、別のスレッドが要素を削除するまでinsertステートメントがブロックされます。公平性の問題は、複数のスレッドが同時に挿入と削除を試みた場合(つまり、キューがブロックされた期間中)に発生することです。公平性アルゴリズムにより、最初に要求されるスレッドが最初に取得されるスレッドになります。そうしないと、特定のスレッドが他のスレッドよりも長く待機し、予測できない動作を引き起こす可能性があります(後で開始した他のスレッドが最初に処理されたため、1つのスレッドが数秒かかることがあります)。トレードオフは、公平性の管理にオーバーヘッドがかかり、スループットが低下することです。
LinkedBlockingQueue
とConcurrentLinkedQueue
の最も重要な違いは、LinkedBlockingQueue
から要素を要求し、キューが空の場合、スレッドは何かがあるまで待機することです。 ConcurrentLinkedQueue
は、空のキューの動作ですぐに戻ります。
あなたはブロッキングが必要かどうかに依存します。多くのプロデューサーと1つのコンシューマーがある場合、そのように聞こえます。一方、多くのコンシューマーと1つのプロデューサーのみが存在する場合は、ブロッキング動作が不要な場合があり、キューが空かどうかをコンシューマーに確認させ、空いている場合は先に進んでもらうことができます。
ConcurrentLinkedQueue は、ロックが取得されないことを意味します(すなわち、synchronized(this)または Lock.lock 呼び出しはありません)。変更中に CAS-比較とスワップ 操作を使用して、ヘッド/テールノードが開始時と同じかどうかを確認します。その場合、操作は成功します。頭部/尾部のノードが異なる場合、ノードは回転して再試行します。
LinkedBlockingQueue は、変更する前にロックを取得します。したがって、オファーの呼び出しは、ロックを取得するまでブロックされます。 TimeUnitを使用するオファーオーバーロードを使用して、追加を放棄する前にX時間だけ待つことを表明できます(通常、Xミリ秒後にメッセージが古くなるメッセージタイプのキューに適しています)。
公平性とは、Lock実装がスレッドの順序を維持することを意味します。つまり、スレッドAが入ってからスレッドBが入った場合、スレッドAは最初にロックを取得します。公平性がなければ、実際に何が起こるかは未定義です。ほとんどの場合、スケジュールされるのは次のスレッドです。
どちらを使用するかは、それによって異なります。私は ConcurrentLinkedQueue を使用する傾向があります。なぜなら、プロデューサーが作業をキューに入れるのにかかる時間はさまざまだからです。まったく同じ瞬間にプロデュースするプロデューサーはあまりいません。しかし、アンケートはナイススリープ状態にならないため、消費者側はより複雑です。それを自分で処理する必要があります。
質問のタイトルには、ブロッキングキューが記載されています。ただし、ConcurrentLinkedQueue
はnotブロッキングキューです。
BlockingQueue
sは、ArrayBlockingQueue
、DelayQueue
、LinkedBlockingDeque
、LinkedBlockingQueue
、PriorityBlockingQueue
、およびSynchronousQueue
です。
これらのいくつかは明らかに目的に適合しません(DelayQueue
、PriorityBlockingQueue
、およびSynchronousQueue
)。 LinkedBlockingQueue
とLinkedBlockingDeque
は、後者が両端キュー(Dequeインターフェイスを実装)であることを除いて同一です。
ArrayBlockingQueue
は、要素の数を制限したい場合にのみ有用なので、LinkedBlockingQueue
に固執します。
ArrayBlockingQueueのメモリフットプリントは小さく、要素ノードを再利用できます。新しい挿入ごとにLinkedBlockingQueue $ Nodeオブジェクトを作成する必要があるLinkedBlockingQueueとは異なります。
SynchronousQueue
(別の 質問 から取得)SynchronousQueue
はハンドオフのようなものですが、LinkedBlockingQueue
は単一の要素のみを許可します。違いは、SynchronousQueue
へのput()
呼び出しは、対応するtake()
呼び出しがあるまで戻りませんが、サイズ1のLinkedBlockingQueue
を使用すると、put()
呼び出し(空のキューへ)がすぐに戻ります。本質的には、キューが本当に必要ない場合(保留中のデータを保持したくない場合)のBlockingQueue
実装です。
LinkedBlockingQueue
(LinkedList
実装ですが、LinkedList
のJDK実装ではありません。静的内部クラスNodeを使用して要素間のリンクを維持します)LinkedBlockingQueueのコンストラクター
public LinkedBlockingQueue(int capacity)
{
if (capacity < = 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node< E >(null); // Maintains a underlying linkedlist. ( Use when size is not known )
}
リンクを維持するために使用されるノードクラス
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
3。 ArrayBlockingQueue(配列の実装)
ArrayBlockingQueueのコンストラクター
public ArrayBlockingQueue(int capacity, boolean fair)
{
if (capacity < = 0)
throw new IllegalArgumentException();
this.items = new Object[capacity]; // Maintains a underlying array
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
IMHOのArrayBlockingQueue
とLinkedBlockingQueue
の最大の違いは、コンストラクターから明らかです基になるデータ構造配列と他のlinkedList。
ArrayBlockingQueue
は single-lock double condition algorithm を使用し、LinkedBlockingQueue
は「2ロックキュー」アルゴリズムのバリアントであり、2つのロック2の条件(takeLock、putLock)があります
ConcurrentLinkedQueueはロックフリーですが、LinkedBlockingQueueはそうではありません。 LinkedBlockingQueue.put()またはLinkedBlockingQueue.take()を呼び出すたびに、最初にロックを取得する必要があります。つまり、LinkedBlockingQueueの同時実行性は不十分です。パフォーマンスを重視する場合は、ConcurrentLinkedQueue + LockSupportを試してください。