GuavaMinMaxPriorityQueueおよびEvictingQueueのガイド
1 。 概要
この記事では、Guavaライブラリからの EvictingQueue、、およびMinMaxPriorityQueueコンストラクトについて説明します。 EvictingQueue は、循環バッファーの概念の実装です。 MinMaxPriorityQueue は、提供されたコンパレータを使用して最小および最大の要素へのアクセスを提供します。
2. EvictingQueue
構築から始めましょう–キューのインスタンスを構築するとき、引数として最大キューサイズを指定する必要があります。
EvictingQueue に新しいアイテムを追加したいときに、キューがいっぱいになると、そのヘッドから要素が自動的に削除されます。
標準のキューの動作と比較すると、キュー全体に要素を追加してもブロックされませんが、head要素が削除され、新しいアイテムがtailに追加されます。
EvictingQueue は、追加のみの方法で要素を挿入するリングとして想像できます。 新しい要素を追加する位置に要素がある場合は、指定された位置にある既存の要素をオーバーライドするだけです。
最大サイズが10のEvictingQueueのインスタンスを作成してみましょう。 次に、それに10個の要素を追加します。
Queue<Integer> evictingQueue = EvictingQueue.create(10);
IntStream.range(0, 10)
.forEach(evictingQueue::add);
assertThat(evictingQueue)
.containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
標準のキュー実装がある場合、完全なキューに新しいアイテムを追加すると、プロデューサーがブロックされます。
これは、EvictingQueueの実装には当てはまりません。 新しい要素を追加すると、ヘッドが削除され、新しい要素がテールに追加されます。
evictingQueue.add(100);
assertThat(evictingQueue)
.containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 100);
EvictingQueue を循環バッファーとして使用することにより、非常に効率的な並行プログラムを作成できます。
3. MinMaxPriorityQueue
MinMaxPriorityQueue は、最小要素と最大要素への常時アクセスを提供します。
最小の要素を取得するには、 peekFirst()メソッドを呼び出す必要があります。 最大の要素を取得するには、 peekLast()メソッドを呼び出すことができます。 これらはキューから要素を削除するのではなく、それを取得するだけであることに注意してください。
要素の順序付けは、このキューのコンストラクターに渡す必要があるコンパレーターによって行われます。
整数型の値フィールドを持つCustomClassクラスがあるとしましょう。
class CustomClass {
private Integer value;
// standard constructor, getters and setters
}
intタイプのコンパレータを使用するMinMaxPriorityQueueを作成しましょう。 次に、CustomClassタイプの10個のオブジェクトをキューに追加します。
MinMaxPriorityQueue<CustomClass> queue = MinMaxPriorityQueue
.orderedBy(Comparator.comparing(CustomClass::getValue))
.maximumSize(10)
.create();
IntStream
.iterate(10, i -> i - 1)
.limit(10)
.forEach(i -> queue.add(new CustomClass(i)));
MinMaxPriorityQueue と渡されたコンパレータの特性により、キューの先頭の要素は1に等しく、キューの末尾の要素は10に等しくなります。 :
assertThat(
queue.peekFirst().getValue()).isEqualTo(1);
assertThat(
queue.peekLast().getValue()).isEqualTo(10);
キューの容量が10で、10個の要素を追加したため、キューがいっぱいになりました。 新しい要素を追加すると、キューの最後の要素が削除されます。 valueが-1に等しいCustomClassを追加しましょう。
queue.add(new CustomClass(-1));
そのアクションの後、キューの最後の要素が削除され、その末尾の新しいアイテムは9に等しくなります。 これは、キューを作成したときに渡したコンパレータによる新しい最小要素であるため、新しいヘッドは-1になります。
assertThat(
queue.peekFirst().getValue()).isEqualTo(-1);
assertThat(
queue.peekLast().getValue()).isEqualTo(9);
MinMaxPriorityQueueの仕様によると、 キューがいっぱいの場合、現在最大の要素よりも大きい要素を追加すると、同じ要素が削除され、事実上無視されます。
100の数字を追加して、その操作の後にそのアイテムがキューにあるかどうかをテストしてみましょう。
queue.add(new CustomClass(100));
assertThat(queue.peekFirst().getValue())
.isEqualTo(-1);
assertThat(queue.peekLast().getValue())
.isEqualTo(9);
ご覧のとおり、キューの最初の要素はまだ-1に等しく、最後の要素は9に等しくなります。 したがって、整数の追加は、キュー内のすでに最大の要素よりも大きいため、無視されました。
4. 結論
この記事では、GuavaライブラリのEvictingQueueおよびMinMaxPriorityQueueコンストラクトについて説明しました。
EvictingQueue を循環バッファーとして使用して、非常に効率的なプログラムを実装する方法を見てきました。
MinMaxPriorityQueueをComparatorと組み合わせて使用し、最小要素と最大要素に常時アクセスできるようにしました。
新しい要素を追加すると、すでにキューにある要素が上書きされるため、提示された両方のキューの特性を覚えておくことが重要です。 これは、キュー全体に新しい要素を追加するとプロデューサースレッドがブロックされるか、例外がスローされる標準のキュー実装とは異なります。
これらすべての例とコードスニペットの実装は、 GitHubプロジェクトにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。