Java マルチスレッド 08 - プロデューサ/コンシューマ パターン

1 コンセプトの紹介

マルチスレッド環境では、多くの場合、複数のスレッドの同時実行性と相互通信が必要になります。その中には、重要なマルチスレッド同時コラボレーション モデル、つまり「プロデューサー/コンシューマー モデル」があります。

2 役割紹介

プロデューサー

データの生成を担当するモジュールは、メソッド、オブジェクト、スレッド、またはプロセスです。

消費者

データの処理を担当するモジュールは、メソッド、オブジェクト、スレッド、またはプロセスです。

バッファ

コンシューマはプロデューサのデータを直接使用することはできません。プロデューサとコンシューマの間には「バッファ」が存在します。プロデューサーは制作したデータやコンテンツを「バッファ」に置き、コンシューマーは処理対象のデータを「バッファ」から取り出します。

バッファーは同時実行性の中核であり、バッファーを設定する利点は次のとおりです。

  • スレッドの同時コラボレーションを実装する

バッファを設定した後、プロデューサ スレッドはデータをバッファに入れるだけでよく、コンシューマの消費をチェックする必要はありません。同様に、コンシューマは処理対象のデータをバッファから取得するだけでよく、チェックする必要はありません。プロデューサーが何を作っているかを明らかにします。このようにして、「プロデューサー スレッド」と「コンシューマー スレッド」の分離が論理的に実現され、プロデューサーとコンシューマーの間の結合が分離されます。

  • 忙しさの偏りを解消し、効率を向上

プロデューサのデータ生成が遅い場合でも、バッファにはデータがまだ残っているため、コンシューマの消費には影響しません。コンシューマのデータ処理が遅い場合でも、プロデューサはバッファにデータを入力し続けることができます。

3 生産者および消費者モデルの実装

3.1 生産および消費されるオブジェクトの作成

public class Food {
    private int id;

    public Food(int id) {
        this.id = id;
    }
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

3.2 バッファの作成

public class BufferBlock {
    //定义存放食物的盒子
    private Food[] foods = new Food[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放食物
     */
    public synchronized void push(Food food){
        //判断盒子是否已满
        while(this.index == this.foods.length){
            try {
                //释放锁
                this.wait();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        //唤醒领取食物的线程
        this.notify();
        this.foods[this.index] = food;
        this.index++;
    }
    /**
     * 取食物
     */
    public synchronized Food pop(){
        while(this.index == 0){
            try {
                //满足条件后,释放锁
                this.wait();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        //唤醒放入食物的线程
        this.notify();
        this.index--;
        return this.foods[this.index];
    }
}

3.3 プロデューサースレッドの作成

public class ProducerThread extends Thread{
    private BufferBlock block;
    public ProducerThread(BufferBlock block){
        this.block = block;
    }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            Food food = new Food(i);
            this.block.push(food);
            System.out.println("生产食物:" + food.getId());
        }
    }
}

3.4 コンシ​​ューマスレッドの作成

public class ConsumerThread extends Thread{
    private BufferBlock block;
    public ConsumerThread(BufferBlock block){
        this.block = block;
    }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            Food pop = this.block.pop();
            System.out.println("消费食物:" + pop.getId());
        }
    }
}

3.5 テストクラスの作成

public class Test {
    public static void main(String[] args) {
        //创建缓冲区
        BufferBlock block = new BufferBlock();
        //启动消费者线程
        new ConsumerThread(block).start();
        //启动生产者线程
        new ProducerThread(block).start();
    }
}

3.6 結果出力

食糧生産: 0

食糧を生産する: 1

食料生産:2

食料生産:3

食料生産:4

食料生産:5

食料生産:6

消費した食料: 0

消費した食料: 6

消費した食料: 5

消費した食料: 4

消費した食料: 3

消費した食料: 2

消費した食料: 1

食料生産:7

食料生産:8

食料生産:9

消費した食料: 9

消費した食料: 8

消費した食料: 7

4 まとめ

生産者と消費者のパターン:

1 生産者と消費者は同じリソースを共有しており、生産者と消費者は相互に依存しており、互いに条件付きです。

2 生産者の場合、データが生成される前に、消費者は待機状態に入る必要があり、データが生成された後、消費者は消費について直ちに通知される必要があります。

3 消費者は、消費後、消費が終了し、消費のために新しいデータを生成し続ける必要があることを生産者に通知する必要があります。

4 また、このモードではバッファーが重要であることがわかり、作業中は主にメッセージ キュー (kafka、ActiveMQ、RockerMQ、RabbitMQ などのさまざまな MQ) を使用して実装されます。

 

おすすめ

転載: blog.csdn.net/QQ156881887/article/details/129171991