今回は BlockingQueue と BlockingDeque の2つ(一覧)。
メソッドは独断と偏見で幾つかにカテゴリー分けしてます:
- 集合としてのメソッド:size() や iterator() など
- 要素の挿入:add(), offer() など
- 要素の削除:remove(), poll() など
- 要素の検査:element(), peek() など
メソッドの役割が分かりにくそうな場合のみ別途説明を。 その他注意点
- 拡張対象のインターフェースに定義されているメソッドには @Override アノテーションを付与してます。 ただし、インターフェースのメソッドに @Override を付与すると実際にはコンパイルエラーになります。
- 配列に関するメソッド toArray(..) はここでは無視してます。
BlockingQueue インターフェース
BlockingQueue は「ブロッキング処理 」(blocking operation) をサポートした Queue です。
package java.util.concurrent; public interface BlockingQueue<E> extends Queue<E>{ // ********** 集合としてのメソッド ********** @Override int size(); @Override boolean isEmpty(); int remainingCapacity(); @Override boolean contains(Object o); @Override boolean containsAll(Collection<?> c); @Override Iterator<E> iterator(); @Override boolean addAll(Collection<? extends E> c); @Override boolean remove(Object o); @Override boolean removeAll(Collection<?> c); @Override boolean retainAll(Collection<?> c); @Override void clear(); int drainTo(Collection<? super E> c); int drainTo(Collection<? super E> c, int maxElements); // ********** 要素の挿入 ********** @Override boolean add(E e) throws IllegalStateException; @Override boolean offer(E e); void put(E e) throws InterruptedException; boolean offer(E e, long timeout, TimeUnit unit); // ********** 要素の削除 ********** @Override E remove() throws IllegalStateException; @Override E poll(); E take() throws InterruptedException; E poll(long timeout, TimeUnit unit); // ********** 要素の検査 ********** @Override E element() throws IllegalStateException; @Override E peek(); }
キューメソッド
BlockingQueue に対して行う処理は、Queue と同じくオブジェクトの挿入、削除、検査の3つです。 Queue と比べて追加されたメソッドは「ブロッキング処理」put(), take() と「タイムアウトのある処理」offer(E, long, TimeUnit), poll(long, TimeUnit) です。
「ブロッキング処理」とは
- キューが空なら、キューに要素が挿入されて取得できるようになるまで待つ
- キューが満杯なら、キューから要素が削除されて挿入できるようになるまで待つ
という処理です。 「タイムアウトのある処理」とは、上記の「ブロッキング処理」の待ち時間を指定して実行する処理です。
キューメソッドをまとめると下表のようになります:
例外を投げる | 失敗時に特定の値を返す / 失敗時に返される値 |
ブロッキング処理 | タイムアウトのある処理 / 失敗時に返される値 |
|
---|---|---|---|---|
挿入 | add(E) | offer(E) / false | put(E) | offer(E, long, TimeUnit) / false |
削除 | remove() | poll() / null | take() | poll(long, TimeUnit) / null |
検査 | element() | peek() / null | - | - |
列挙型 TimeUnit
「タイムアウトのある処理」を行うメソッド offer(E, long, TimeUnit), poll(long, TimeUnit) の引数に指定する列挙型 TimeUnit を見ていきましょう。 これは「時間の単位」を表す列挙型です*1。
package java.util.concurrent; public enum TimeUnit extends Enum<TimeUnit>{ DAYS, // 日 HOURS, // 時間 MINUTES, // 分 SECONDS, // 秒 MILLISECONDS, // ミリ秒 MICROSECONDS, // マイクロ秒 NANOSECONDS // ナノ秒 }
各単位の関係を書き下すと次のようになります。
1 day = 24 hours
1 hour = 60 minutes
1 minute = 60 seconds
1 second = 1000 milliseconds
1 millisecond = 1000 microseconds
1 microsecond = 1000 nanoseconds
ちょっと自己満足的な表を書き下すとこんな感じ。
DAYS (d) | HOURS (h) | MINUTES (m) | SECONDS (s) | MILLISECONDS (ms) | MICROSECONDS (μs) | NANOSECONDS (ns) | |
---|---|---|---|---|---|---|---|
1 d | = 1 d | = 24 h | = 1440 m | = 86400 s | = 8.64×107 ms | = 8.64×1010 μs | = 8.64×1013 ns |
1 h | = 1 h | = 60 m | = 3600 s | = 3.6×106 ms | = 3.6×109 μs | = 3.6×1012 ns | |
1 m | = 1 m | = 60 s | = 6×104 ms | = 6×107 μs | = 6×1010 ns | ||
1 s | = 1 s | = 103 ms | = 106 μs | = 109 ns | |||
1 ms | = 10-3 s | = 1 ms | = 103 μs | = 106 ns | |||
1 μs | = 10-6 s | = 10-3 ms | = 1 μs | = 103 ns | |||
1 ns | = 10-9 s | = 10-6 ms | = 10-3 μs | = 1 ns |
drainTo() メソッド
BlockingQueue#drainTo(Collection) メソッドは、このキューから要素を全て削除し、それらを引数のコレクションに加えるメソッドです。 このメソッドは BlockingQueue#poll() とCollection#add(E) を用いるのと同様の処理ですが、より効率的に行えるようになっています。
- drain・・・流出する(FF の魔法にあったっけ?)
BlockingDeque インターフェース
BlockingDeque はブロッキング処理をサポートした Deque です。
package java.util.concurrent; public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E>{ // ********** 集合としてのメソッド ********** @Override int size(); @Override boolean isEmpty(); @Override int remainingCapacity(); @Override boolean contains(Object o); @Override boolean containsAll(Collection<?> c); @Override Iterator<E> iterator(); @Override Iterator<E> descendingIterator(); @Override boolean addAll(Collection<? extends E> c); @Override boolean remove(Object o); @Override boolean removeAll(Collection<?> c); @Override boolean retainAll(Collection<?> c); @Override void clear(); @Override boolean removeFirstOccurrence(Object o); @Override boolean removeLastOccurrence(Object o); @Override int drainTo(Collection<? super E> c); @Override int drainTo(Collection<? super E> c, int maxElements); // ********** 要素の挿入 ********** @Override boolean add(E e) throws IllegalStateException; @Override void addFirst(E e) throws IllegalStateException; @Override void addLast(E e) throws IllegalStateException; @Override boolean offer(E e); @Override boolean offerFirst(E e); @Override boolean offerLast(E e); @Override void push(E e) throws IllegalStateException; @Override boolean offer(E e, long timeout, TimeUnit unit); boolean offerFirst(E e, long timeout, TimeUnit unit); boolean offerLast(E e, long timeout, TimeUnit unit); @Override void put(E e) throws InterruptedException; void putFirst(E e) throws InterruptedException; void putLast(E e) throws InterruptedException; // ********** 要素の削除 ********** @Override E remove() throws IllegalStateException; @Override E removeFirst() throws IllegalStateException; @Override E removeLast() throws IllegalStateException; @Override E poll(); @Override E pollFirst(); @Override E pollLast(); @Override E pop() throws IllegalStateException; @Override E poll(long timeout, TimeUnit unit); E pollFirst(long timeout, TimeUnit unit); E pollLast(long timeout, TimeUnit unit); @Override E take() throws InterruptedException; E takeFirst() throws InterruptedException; E takeLast() throws InterruptedException; // ********** 要素の検査 ********** @Override E element() throws IllegalStateException; @Override E getFirst() throws IllegalStateException; @Override E getLast() throws IllegalStateException; @Override E peek(); @Override E peekFirst(); @Override E peekLast(); }
説明いらないよね?
*1:正直、このモデル化はあまり良くない気がします。 offer(E, long, TimeUnit) や poll(long, TimeUnit) は long と TimeUnit を個別に引数として受け取ってますが、これらをまとめてオブジェクトにした方が自然な気がします。 例えば、TimeInterval クラスを定義し、static メソッド TimeInterval#valueOfDays(long) や TimeInterval#valueOfNanoSeconds(long) のような static ファクトリメソッドによってインスタンスを取得できるようにするってのが素直な実装かと。 これを用いて offer(E, TimeInterval), poll(TimeInterval) のようなメソッドを定義すれば良いのではと。