1. 生産者/消費者パターンとは?
特定のモジュールは、別のモジュールによって処理されるデータの生成を担当します (ここでのモジュールは一般化されており、クラス、関数、スレッド、プロセスなどにすることができます)。データを生成するモジュールはプロデューサーと呼ばれ、データを処理するモジュールはコンシューマーと呼ばれます。生産者と消費者の間に緩衝地帯が追加され、これを倉庫と呼び、生産者は倉庫に商品を入れる責任があり、消費者は倉庫から商品を取り出す責任があります.モデルです。
構造図は次のとおりです。
第二に、生産者消費者モデルの利点:
1. デカップリング:
バッファーが存在するため、プロデューサーとコンシューマーの間に直接的な依存関係はなく、結合の程度が減少します。
2. 同時実行をサポート:
プロデューサとコンシューマは2つの独立した並行体であるため、ブリッジとしてバッファで接続されています. プロデューサはデータをバッファに投げ込むだけで次のデータを生成し続けることができます.互いの処理速度によってブロックされないようにします。
3.不均一な忙しさをサポート:
バッファには別の利点があります。バッファの利点は、データが生成される速度が速い場合と遅い場合に明らかになります。データが迅速に生成されると、コンシューマーはそれを処理する時間がなく、未処理のデータが一時的にバッファーに格納される可能性があります。生産者の製造スピードが遅くなると、消費者はゆっくりとそれを処分します。
3. プロデューサー/コンシューマー モデル [つまり、「プロデューサー-ストレージ-コンシューマー」] モデルが従うルール:
1.生産者は、倉庫が満杯でないときだけ生産し、倉庫が満杯になると生産を停止します。
2.消費者は、倉庫に商品があるときだけ消費でき、倉庫が空になったら待つことができます。
3.消費者は、消費する製品が倉庫にないことに気付いた場合、生産者に生産するよう通知します。
4. 生産者が消耗品を生産する場合、待機中の消費者にそれを消費するように通知する必要があります。
4. ソースコード例:
1. 倉庫:
package com.hongri.designpattern.producer_consumer;
import java.util.LinkedList;
/**
* 仓库【即共享数据区域】
*/
public class SyncStack {
LinkedList<Integer> list = new LinkedList<>();
int capacity = 10;
public volatile int index;
/**
* 供生产者调用
*
* @param value
*/
public synchronized void push(String producerName, int value) {
while (list.size() >= capacity) {
try {
System.out.println("仓库已满 ---> 生产者--进入wait状态");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//没有满,则继续produce
System.out.println("生产者--" + producerName + "--生产了:" + value);
list.add(value);
//唤醒其他所有处于wait()的线程,包括消费者和生产者
notifyAll();
}
/**
* 供消费者调用
*
* @return
*/
public synchronized int pop(String consumerName) {
int val = 0;
while (list.size() == 0) {
try {
System.out.println(" 仓库无货 ---> 消费者--进入wait状态");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果有数据,继续consume
val = list.removeFirst();
System.out.println(" 消费者------" + consumerName + "--消费了:" + val);
notifyAll();
return val;
}
}
2. プロデューサー:
package com.hongri.designpattern.producer_consumer;
import java.util.Random;
/**
* 生产者
*/
public class Producer implements Runnable {
private String name;
private SyncStack stack;
public Producer(String name, SyncStack stack) {
this.name = name;
this.stack = stack;
}
@Override
public void run() {
while (true) {
int value = new Random().nextInt(100);
stack.push(name, value);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3. 消費者:
package com.hongri.designpattern.producer_consumer;
/**
* 消费者
*/
public class Consumer implements Runnable{
private String name;
private SyncStack stack;
public Consumer(String name, SyncStack stack) {
this.name = name;
this.stack = stack;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
int val = stack.pop(name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4. 電話:
SyncStack stack = new SyncStack();
Producer producer1 = new Producer("Producer1", stack);
Producer producer2 = new Producer("Producer2", stack);
Producer producer3 = new Producer("Producer3", stack);
Consumer consumer1 = new Consumer("Consumer1", stack);
Consumer consumer2 = new Consumer("Consumer2", stack);
Consumer consumer3 = new Consumer("Consumer3", stack);
new Thread(producer1).start();
new Thread(producer2).start();
new Thread(producer3).start();
new Thread(consumer1).start();
new Thread(consumer2).start();
new Thread(consumer3).start();
テスト結果:
参考:
Java デザイン パターンの概要
Producer Consumer デザイン パターン スレッド プールでのアプリケーション