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クラスを使用してください。このクラスは高速であり、メモリを効率よく使用します。
まとめ
この記事では、オブジェクトの編成とパフォーマンス上の制約に基づいてコレクションを選択する方法を説明しました。
