ノンブロッキングキュー

リンクされたノード上のスレッドセーフで最も重要な非ブロッキングのキュー実装。

ConcurrentLinkedQueue<E> - ガベージ コレクターと連携するように適応された待機なしアルゴリズムを使用します。このアルゴリズムは CAS 上に構築されているため、非常に効率的で高速です。size()メソッドは長時間実行される可能性があるため、常にプルしないことをお勧めします。

ConcurrentLinkedDeque<E> - Deque はダブルエンドキューの略です。これは、データを両側から追加および取得できることを意味します。したがって、このクラスは、FIFO (先入れ先出し) と LIFO (後入れ先出し) の両方の動作モードをサポートします。

実際には、 LIFO が絶対に必要な場合はConcurrentLinkedDequeを使用する必要があります。これは、ノードの双方向性により、このクラスはConcurrentLinkedQueueと比較してパフォーマンスが半分低下するためです。

import java.util.concurrent.ConcurrentLinkedQueue;

public class  ConcurrentLinkedQueueExample {
   public static void main(String[] args) {
       ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

       Thread producer = new Thread(new Producer(queue));
       Thread consumer = new Thread(new Consumer(queue));

       producer.start();
       consumer.start();
   }
}

class Producer implements Runnable {

   ConcurrentLinkedQueue<String> queue;
   Producer(ConcurrentLinkedQueue<String> queue){
       this.queue = queue;
   }
   public void run() {
       System.out.println("Class for adding items to the queue");
       try {
           for (int i = 1; i < 5; i++) {
               queue.add("Item #" + i);
               System.out.println("Added: Item #" + i);
               Thread.sleep(300);
           }
       } catch (InterruptedException ex) {
           ex.printStackTrace();
           Thread.currentThread().interrupt();
       }
   }
}

class Consumer implements Runnable {

   ConcurrentLinkedQueue<String> queue;
   Consumer(ConcurrentLinkedQueue<String> queue){
       this.queue = queue;
   }

   public void run() {
       String str;
       System.out.println("Class for getting items from the queue");
       for (int x = 0; x < 5; x++) {
           while ((str = queue.poll()) != null) {
               System.out.println("Pulled out: " + str);
           }
           try {
               Thread.sleep(600);
           } catch (InterruptedException ex) {
               ex.printStackTrace();
               Thread.currentThread().interrupt();
           }
       }
   }
}

キューのブロック

BlockingQueue<E>インターフェイス- データが大量にある場合、ConcurrentLinkedQueue だけでは十分ではありません。

スレッドがそのジョブを実行できない場合、簡単にOutOfMemmoryException が発生する可能性があります。このようなケースが発生しないように、キューを埋めて操作するためのさまざまなメソッドと条件付きロックを使用して作業するためのBlockingQueueを用意しています。

BlockingQueue はnull 要素を認識しないため、そのような要素を追加または取得しようとするとNullPointerException をスローします。タイムアウト内に要素がキューに配置されなかった場合、poll メソッドは null 要素を返します。

BlockingQueue<E> の実装

それぞれのBlockingQueue実装を詳しく見てみましょう。

ArrayBlockingQueue<E> は、クラシック リング バッファ上に構築されたブロッキング キュー クラスです。ここでは、ロックの「正直さ」を管理する機会があります。Fair=false (デフォルト) の場合、スレッドの順序は保証されません。

DelayQueue<E extends Delayed> は、 DelayedインターフェイスのgetDelayメソッドを通じて各要素で定義された特定の遅延の後にのみキューから要素を取得できるようにするクラスです。

LinkedBlockingQueue<E>はリンク ノード上のブロッキング キューで、「2 ロック キュー」アルゴリズムに実装されています。最初のロックは追加用で、2 番目のロックはキューから要素をプルするためのものです。ロックのため、 ArrayBlockingQueueと比較して、このクラスはパフォーマンスが高くなりますが、より多くのメモリを必要とします。キューのサイズはコンストラクターを介して設定され、デフォルトでは Integer.MAX_VALUE に等しくなります。

PriorityBlockingQueue<E> は、PriorityQueueのマルチスレッド ラッパーです。コンパレータは、要素が追加されるロジックを担当します。最小の要素が最初に表示されます。

SynchronousQueue<E> - キューは FIFO (先入れ先出し) の原則に従って機能します。各挿入操作は、「コンシューマー」スレッドがキューから要素をプルするまで「プロデューサー」スレッドをブロックします。逆も同様で、「コンシューマー」は「プロデューサー」が要素を挿入するまで待機します。

BlockingDeque<E> は、双方向ブロッキング キューの追加メソッドを記述するインターフェイスです。データはキューの両側から挿入および取り出すことができます。

LinkedBlockingDeque<E>は、リンク ノード上の双方向ブロッキング キューで、1 つのロックを持つ単純な双方向リストとして実装されます。キューのサイズはコンストラクターを介して設定され、デフォルトでは Integer.MAX_VALUE に等しくなります。

TransferQueue<E> - このインターフェイスは、要素がキューに追加されると、別のConsumerスレッドがキューから要素をプルするまで、挿入するProducerスレッドをブロックできるという点で興味深いものです。特定のタイムアウトのチェックを追加したり、保留中のConsumer のチェックを設定したりすることもできます。その結果、非同期メッセージと同期メッセージをサポートするデータ転送メカニズムが得られます。

LinkedTransferQueue<E> は、 Slack アルゴリズムを使用したデュアル キューに基づくTransferQueue の実装ですアイドル時に CAS (上記を参照) とスレッド パーキングを多用します。