前回の記事では、Java並行プログラミングのツールであるBlockingQueueインターフェース、ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueueを紹介しました。この記事はシリーズの6番目の記事です。
この記事では、BlockingQueueインターフェイスの実装クラスである並行プログラミングコレクションクラスSynchronousQueueを紹介します。すべてのBlockingQueueインターフェイス実装クラスとは異なります。SynchronousQueueキューの容量は常に0です(または、容量が1のキューとして理解できますが、キューの容量が1であるとは正確ではありません)。 SynchronousQueueは実際には実際のキューではありません。キュー内の要素のストレージスペースを維持しないため、複数のスレッド間のデータ交換のための単なる媒体です。
SynchronousQueue
キューの1つのスレッドの挿入アクションは、常に別のスレッドの削除操作を待機します。その逆も同様です。put()
このメソッドは、要素オブジェクトをSynchronousQueueに配置しますが、別のスレッドが実行されtake()
て要素オブジェクトが削除されるまで、結果は(ブロッキング状態で)返されません。peek()
このメソッドは、BlockingQueueインターフェイス実装クラスの要素を取得できますが、キューから要素を削除しません。ただし、このメソッドはSynchronousQueueキューでは使用できません。
SynchronousQueue同期キューの例
以下にSynchronousQueue
、特性と使用法を理解するのに役立つ例を示します。SynchronousQueueProducer.javaはスレッドを開始し、整数オブジェクトを毎秒キューに入れます。
public class SynchronousQueueProducer implements Runnable {
protected BlockingQueue<Integer> blockingQueue;
public SynchronousQueueProducer(BlockingQueue<Integer> queue) {
this.blockingQueue = queue;
}
@Override
public void run() {
int i = 0;
while (true) {
System.out.println(Thread.currentThread().getName() + " Put: " + ++i);
try {
blockingQueue.put(i);
Thread.sleep(1000); //每隔一秒生产一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SynchronousQueueConsumer.javaはスレッドを開始し、5秒ごとにキューから要素オブジェクトを取り出します。
public class SynchronousQueueConsumer implements Runnable {
protected BlockingQueue<Integer> blockingQueue;
public SynchronousQueueConsumer(BlockingQueue<Integer> queue) {
this.blockingQueue = queue;
}
@Override
public void run() {
while (true) {
try {
Integer data = blockingQueue.take();
System.out.println(Thread.currentThread().getName() + " take(): " + data);
Thread.sleep(5000); //每隔5秒消费一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
SynchronousQueueExample.javaは、新しいSynchronousQueue同期キューを作成し、オブジェクトを挿入するためのプロデューサースレッドを開始し、2つのコンシューマースレッドがオブジェクトを削除します。テストして効果を確認します。
public class SynchronousQueueExample {
public static void main(String[] args) {
final BlockingQueue<Integer> synchronousQueue = new SynchronousQueue<>();
SynchronousQueueProducer queueProducer = new SynchronousQueueProducer(synchronousQueue);
new Thread(queueProducer).start();
SynchronousQueueConsumer queueConsumer1 = new SynchronousQueueConsumer(synchronousQueue);
new Thread(queueConsumer1).start();
SynchronousQueueConsumer queueConsumer2 = new SynchronousQueueConsumer(synchronousQueue);
new Thread(queueConsumer2).start();
}
}
実験の結果を分析すると、Thread-0はプロデューサースレッドであり、Thread-1とThread-2はコンシューマースレッドです。実験結果から、SynchronousQueueは、1回生成、1回消費、1回生成、1回消費する必要があることがわかります。このルールは、コンシューマスレッドとプロデューサースレッドがいくつあっても従う必要があります。
Thread-0 Put: 1
Thread-1 take(): 1
Thread-0 Put: 2
Thread-2 take(): 2
Thread-0 Put: 3
Thread-1 take(): 3
Thread-0 Put: 4
Thread-2 take(): 4
Thread-0 Put: 5
Thread-1 take(): 5
Thread-0 Put: 6
Thread-2 take(): 6
Thread-0 Put: 7
Thread-1 take(): 7
Thread-0 Put: 8
Thread-2 take(): 8
Thread-0 Put: 9
Thread-1 take(): 9
Thread-0 Put: 10
Thread-2 take(): 10
Thread-0 Put: 11
Thread-1 take(): 11
Thread-0 Put: 12
Thread-2 take(): 12
アプリケーションシナリオ:プロデューサーからのリクエスト数がわからないが、これらのリクエストを迅速に処理する必要がある場合は、SynchronousQueueと連携して、プロデューサーリクエストごとにコンシューマースレッドを割り当てるのが最も効率的な処理方法です。Executors.newCachedThreadPool()は下部でSynchronousQueueを使用し、このスレッドプールは要求に応じて新しいスレッドを作成します。
私のブログをフォローすることを歓迎します、多くのブティックコレクションがあります
- この記事は、出典を示して複製されています(接続を添付する必要があり、テキストのみを複製することはできません):レターブラザーのブログ。
あなたがそれがあなたに役立つと思うなら、私のためにそれを好きにして共有してください!あなたのサポートは私の尽きることのない創造的な動機です!。また、最近、以下のような高品質なコンテンツを出力しておりますので、よろしくお願いいたします。