マルチスレッドブロッキングキュー(生産者/消費者モデル)

ブロッキングキュー

生産者/消費者モデル

  • 生産者/消費者モデルは、コンテナを介した生産者と消費者の間の強い結合の問題を解決することです。プロデューサーとコンシューマーは互いに直接通信しませんが、ブロッキングキューを介して通信するため、プロデューサーは、データの生成後にコンシューマーがデータを処理するのを待つ必要がなく、データをブロッキングキューに直接スローします。コンシューマーはプロデューサーにデータを要求しませんが、ブロッキングキューから直接取得されるブロッキングキューは、プロデューサーとコンシューマーの処理機能のバランスをとるバッファーと同等です。このブロッキングキューは、プロデューサーとコンシューマーを分離するために使用されます

モデルはwait()とnotify()の2つのメソッドを使用する必要があることをご存知だと思います(1つは待機中、もう1つはウェイクアップ中)

1. Object.wait()メソッドを使用する必要があります(wait)

  • wait()メソッドは、スレッドの実行を停止します
  1. wait()メソッドの機能は、現在コードを実行しているスレッドを待機させることです。wait()メソッドはObjectクラスのメソッドです。このメソッドは、現在のスレッドを「実行前キュー」に入れるために使用されます。 wait()が見つかりました。コードは、通知または中断されるまで実行を停止します。
  2. wait()メソッドは、同期メソッドまたは同期ブロックでのみ呼び出すことができます待機()が呼び出されたときに適切なロックが保持されていない場合は例外がスローされます
  3. wait()メソッドが実行された後、現在のスレッドはロックを解放し、スレッドは他のスレッドと競合してロックを再取得します。
public class MyWait {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Object object = new Object();
        synchronized (object){
    
    
            System.out.println("等待中..");
            object.wait();
            System.out.println("等待已过...");
        }
        System.out.println("main方法结束...");
    }
}

このように、object.wait()の実行後、それは永久に待機しているので、プログラムは永久に待機できてはなりませんこのとき、notify()をウェイクアップするには別のメソッドを使用する必要があります。
ここに画像の説明を挿入

2. Object.notify()メソッドを使用する必要があります(ウェイクアップ)

  • notifyメソッドは、停止したスレッドを実行し続けることです。
  1. notify()メソッドは、同期メソッドまたは同期ブロックでも呼び出す必要があります。このメソッドは、オブジェクトのオブジェクトロックを待機している可能性のある他のスレッドに通知し、通知し、オブジェクトのオブジェクトロックを再取得させるために使用されます。 。複数のスレッドが待機している場合、スレッドプランナーは待機状態のスレッドをランダムに選択します。
  2. 通知()メソッドの後に、現在のスレッドが直ちにオブジェクトロックを解除しないであろうスレッドの実行は、プログラム実行()メソッドに通知されるまでそのオブジェクトのロックを解放するブロックの出口を同期されます

3.ブロッキングキューコードのデモンストレーション

ブロッキングキュー:ArrayBlockingQueueクラス

package com.zg;

/**
 * 采用顺序表实现的阻塞式队列
 * //1.首先解决线程安全问题:经过分析,在方法上面见synchronized;
 * //2.解决通知机制:
 * 调offer的有可能去唤醒poll,调用poll的有可能去唤醒offer
 */

/**
 * 生产者只调用offer
 * 消费者只调用poll
 */
public class ArrayBlockingQueue {
    
    
    private Integer[] array = new Integer[5];
    private int size = 0;
    private int headIndex = 0;//队列中的第一个元素的下标
    private int rearIndex = 0;//队尾中,下一个可以放入元素的下标(也就是队尾元素所在下标的下一个)

    public synchronized boolean offer(Integer e) throws InterruptedException {
    
    
        //临界区开始
        while (size >= array.length){
    
    //满了
            this.wait();//Object.wait();//有可能你醒过来,条件还没有满足,因为不知道谁唤醒的,所以使用while
        }

        array[rearIndex] = e;
        rearIndex++;
        if (rearIndex == array.length){
    
    
            rearIndex = 0;
        }
        size++;

        notifyAll();//大赦天下
        //临界区结束
        return true;
    }

    public synchronized Integer poll() throws InterruptedException {
    
    
        while (size <= 0){
    
    
            wait();//有可能你醒过来,条件还没有满足,因为不知道谁唤醒的,所以使用while
        }

        Integer e = array[headIndex];
        headIndex++;
        if (headIndex == array.length){
    
    
            headIndex = 0;
        }
        size--;

        notifyAll();//大赦天下
        return e;
    }
}

生産者/消費者クラス:QueueDemoクラス

package com.zg;

public class QueueDemo {
    
    
    static ArrayBlockingQueue queue = new ArrayBlockingQueue();

    //生产者
    static class Producer extends Thread{
    
    
        @Override
        public void run() {
    
    
            setName("生产者");
           while(true){
    
    
               try {
    
    
                   queue.offer(1);
               } catch (InterruptedException e) {
    
    
                   e.printStackTrace();
               }
           }
        }
    }


    //消费者
    static class Consumer extends Thread{
    
    
        @Override
        public void run() {
    
    
            setName("消费者");
            try {
    
    
                queue.poll();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
        for (int i = 0;i < 5;i++){
    
    
            Thread t1 = new Producer();//生产者
            t1.start();
        }

        for (int i = 0;i < 5;i++){
    
    
            Thread t = new Consumer();//消费者
            t.start();
        }
    }
}

おすすめ

転載: blog.csdn.net/qq_45665172/article/details/113818222