Queueクラス
キューはその中に含まれるオブジェクトに順序を課します。キューには順序の末尾にオブジェクトを追加する操作と順序の先頭からオブジェクトを削除する操作が備わっています。キューではオブジェクトが追加された順序をキュー内容の順序付けに使用するのが最も一般的です。オブジェクトの追加順序を使用するキューはFIFO(first in, first out)構造と呼ばれることもあります。
コレクションをキューとして編成するクラスはQueue
インターフェースを実装しています。Queue
インターフェースで定義されているメソッドは即座に戻ります。つまり、空のキューからオブジェクトを削除する試みは失敗し、呼び出されたメソッドに応じて、nullが返されるか例外が生成されます。また、サイズが制限されている満杯のキューにオブジェクトを追加する試みは失敗し、falseが返されるか例外が生成されます。
コレクションをキューとして編成するクラスの中には、Queue
のサブインターフェースであるBlockingQueue
インターフェースを実装しているものがあります。BlockingQueue
インターフェースはQueue
のメソッドに加えて、キューが空または満杯でも即座に戻らないことのあるメソッドも持っています。put
メソッドはキューが満杯でなくなるまで戻らずに待機します。つまり「ブロック」します。take
メソッドはキューが空でなくなるまでブロックします。類似したメソッドとしてoffer
とpoll
もあり、これらはブロックしている間に指定の期間が過ぎるとタイムアウトします。
使用すべき編成がキューだと判明した場合は、以下の記述を参考にしてクラスを選択してください。
- LinkedList:
LinkedList
クラスを使用すると、オブジェクトをキューに編成して、オブジェクトが追加されたときの順序を維持できます。add
メソッドとremove
メソッドの実行に要する時間は短く、この時間はキュー内のオブジェクトの数に左右されません。LinkedList
クラスをベースにしたキューはブロックしません。 - PriorityQueue:
PriorityQueue
オブジェクトはキュー内のオブジェクトを指定の順序でソートされた状態に保ちます。add
メソッドとremove
メソッドの実行に要する時間はキュー内のオブジェクトの数に比例します。PriorityQueue
クラスをベースにしたキューはブロックしません。 - PriorityBlockingQueue:
PriorityBlockingQueue
オブジェクトはキュー内のオブジェクトを指定の順序でソートされた状態に保ちます。add
メソッドとremove
メソッドの実行に要する時間はキュー内のオブジェクトの数に比例します。PriorityQueue
をベースにしたキューにはブロックするメソッドが含まれています。 - ArrayBlockingQueue:
ArrayBlockingQueue
クラスを使用すると、オブジェクトをキューに編成して、オブジェクトが追加されたときの順序を維持できます。add
メソッドとremove
メソッドの実行に要する時間は短く、この時間はキュー内のオブジェクトの数に左右されません。ArrayBlockingQueue
クラスをベースにしたキューはブロックできます。複数のスレッドがキューに対して操作を実行しようと待機している状況では、LinkedBlockingQueue
よりもArrayBlockingQueue
オブジェクトの動作の方が一貫性があって予測しやすいでしょう。オブジェクトのブロックされたメソッド呼び出しが戻るのを複数のスレッドが待っている場合、通常なら、それらのメソッド呼び出しがどんな順序で戻るかは不確実です。ArrayBlockingQueue
クラスのコンストラクタへのオプションの引数を使用すると、ArrayBlockingQueue
オブジェクトのブロックされたメソッド呼び出しを呼び出し順に戻らせるように指定できます。ArrayBlockingQueue
クラスには、ArrayBlockingQueue
オブジェクトの容量をコンストラクタへの引数で指定しなければならないという制約があります。その後、ArrayBlockingQueue
オブジェクトの容量を変更することはできません。 - LinkedBlockingQueue:
LinkedBlockingQueue
クラスを使用すると、オブジェクトをキューに編成して、オブジェクトが追加されたときの順序を維持できます。add
メソッドとremove
メソッドの実行に要する時間は短く、この時間はキュー内のオブジェクトの数に左右されません。LinkedBlockingQueue
クラスをベースにしたキューはブロックできます。複数のスレッドがキューに対して操作を実行しようと待機している状況では、LinkedBlockingQueue
よりもArrayBlockingQueue
オブジェクトの動作の方が一貫性があって予測しやすいでしょう。しかし、LinkedBlockingQueue
クラスを使用した方がスループットが向上することもあります。 - ConcurrentLinkedQueue:
ConcurrentLinkedQueue
クラスを使用すると、オブジェクトをキューに編成して、オブジェクトが追加されたときの順序を維持できます。多数のスレッドがオブジェクトをキューに出し入れしようとする状況にはConcurrentLinkedQueue
クラスが適しています。なぜなら、ConcurrentLinkedQueue
に対しては同時に複数のスレッドが安全に変更を加えることができるからです。ロックは必要ありません。ConcurrentLinkedQueue
に対してオブジェクト追加/削除するためのメソッドは、キュー内のオブジェクトの数と関係なく一定の時間で実行されます。ただし、size
操作に要する時間はキュー内のオブジェクトの数に比例します。 - DelayQueue:
DelayQueue
はキュー内のオブジェクトをいつキューから削除できるのか調べる特殊化されたブロッキングキューです。DelayQueue
内のオブジェクトはDelayed
インターフェースを実装していなければなりません。Delayed
インターフェースで定義されているgetDelay
メソッドは指定の時間単位で表された遅延時間を返します。遅延時間が正値になっているオブジェクトをDelayQueue
から削除することはできません。 - SynchronousQueue:
SynchronousQueue
クラスはオブジェクトのプロデューサとコンシューマを調整するための特殊化されたクラスです。SynchronousQueue
クラスはブロックします。SynchronousQueue
オブジェクトは常に空です。SynchronousQueue
オブジェクトのput
メソッドは、別のスレッドがそのオブジェクトのtake
メソッドが戻るのを待っていない限りブロックします。SynchronousQueue
オブジェクトのtake
メソッドは、別のスレッドがそのオブジェクトのput
メソッドが戻るのを待っていない限りブロックします。
Dequeクラス
デック(deque)は、どちらの端でも要素を追加/削除できる両端キューです。
コレクションをデックとして編成するクラスはDeque
インターフェースを実装しています。Deque
インターフェースで定義されているメソッドは即座に戻ります。つまり、空のデックからオブジェクトを削除する試みは失敗し、呼び出されたメソッドに応じて、nullが返されるか例外が生成されます。また、サイズが制限されている満杯のデックにオブジェクトを追加する試みは失敗し、falseが返されるか例外が生成されます。
コレクションをデックとして編成するクラスの中には、Deque
のサブインターフェースであるBlockingDeque
インターフェースを実装しているものがあります。BlockingDeque
インターフェースはDeque
のメソッドに加えて、キューが空または満杯でも即座に戻らないことのあるメソッドも持っています。putFirst
メソッドとputLast
メソッドはキューが満杯でなくなるまで戻らずに待機(ブロック)します。takeFirst
メソッドとtakeLast
メソッドはキューが空でなくなるまでブロックします。類似したメソッドとして、ブロックしている間に指定の期間が過ぎるとタイムアウトするメソッドもあります。
使用すべき編成がデックだと判明した場合は、以下の記述を参考にしてクラスを選択してください。
- ArrayDeque:
ArrayDeque
クラスを使用すると、オブジェクトをデックに編成できます。追加操作と削除操作に要する時間は短く、この時間はデック内のオブジェクトの数に左右されません。ArrayDeque
クラスをベースにしたデックはブロックしません。多くの場合、デックの管理にはArrayDeque
クラスが最適です。しかし、LinkedList
の方が速い場合もあります。パフォーマンスを重視する場合は、アプリケーションにとってLinkedList
の方が有利かどうか実際に試してください。 - LinkedList:
LinkedList
クラスを使用すると、オブジェクトをデックに編成できます。add
メソッドとremove
メソッドの実行に要する時間は短く、この時間はキュー内のオブジェクトの数に左右されません。LinkedList
クラスをベースにしたデックはブロックしません。 - LinkedBlockingDeque:
LinkedBlockingDeque
クラスを使用すると、オブジェクトをキューに編成できます。LinkedBlockingDeque
クラスにはブロックするメソッドがあります。
Stackクラス
スタックはその中に含まれるオブジェクトに順序を課して、最後に追加されたオブジェクトが次に削除されるオブジェクトとなるようにします。スタックはLIFO(last in, first out)構造と呼ばれることもあります。コレクション用にサポートされている他の編成と違って、スタックを編成するためのクラスに共通するインターフェースはありません。
使用すべき編成がスタックだと判明した場合は、以下の記述を参考にしてクラスを選択してください。
- 新しいコードには
Stack
クラスを使用しないでください。Stack
クラスは設計がよくありません。このクラスのメソッドはすべて同期化されているため、不必要なオーバーヘッドが生じる可能性があります。 - Javaには
Stack
インターフェースが用意されていないので、いずれかのDequeクラスを使ってスタックを実装してください。スタック編成のサポートに必要な操作はデック用の操作のサブセットです。
コレクションクラスのパフォーマンス
コレクション内でのオブジェクトの編成方法には特にこだわらないという開発者であれば、それ以外の関心事はパフォーマンスだけでしょう。その場合は、ArrayList
クラスを使用してください。このクラスは高速であり、メモリを効率よく使用します。
まとめ
この記事では、オブジェクトの編成とパフォーマンス上の制約に基づいてコレクションを選択する方法を説明しました。