Why does the producer consumer pattern use a while loop instead of an if statement

Keywords: Java RabbitMQ JavaSE

1, Producer consumer mode (there are only two threads, one is producer thread and the other is consumer thread)

a key!!!!!!! When reading this blog, first describe the wait mechanism of the wait () method. When the first thread is waiting, it will release the lock. When the thread is awakened, it will continue to execute from the code behind the wait method. This point is also the finishing touch of this article, the top priority. That's why you don't use if while.

Whisper bb: I also read many articles to know that the thread is blocked. After being awakened, I will continue to execute the code behind the thread wait method. I had been foolishly thinking that this thread would be re executed after it was blocked. I'm the rookie. I'm the colored pen.

First, let's take a look at the case where there is only one producer thread and one consumer thread. At this time, if (when there are multiple producer and consumer threads, you must use while, which will be described below) will not cause data errors, because only two threads will wake up all threads when calling this.notifyAll(), but there is only one waiting thread at this time. The code is as follows:

package com.aa.Producer consumer model;

public class A {

    public static void main(String[] args) {
        Data data = new Data();

        //Producer thread A1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"producer A1").start();

        //Consumer thread B1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"consumer B1").start();

    }


}

//This is the shared area data, which has only one attribute num
class Data{
    private int num=0;

    //Producer pair num++
    public synchronized void increment() throws InterruptedException {
        
        //I deliberately use if. There will be no error here, because there are only two threads, and only the consumer thread can be awakened. For num--
        if(num!=0){
            this.wait();  //At this time, the thread is blocked, so that the thread will continue to execute subsequent code after being awakened, which is why you don't use if while
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==="+num);
        //Wake up other threads
        this.notifyAll();
    }

    //Consumer satisfaction with num--
    public synchronized void decrement() throws InterruptedException {

        //I deliberately use if. There will be no error here, because there are only two threads, and only the producer thread can be awakened
        if (num==0){
            this.wait();//At this time, the thread is blocked, so that the thread will continue to execute subsequent code after being awakened, which is why you don't use if while
        }

        num--;

        System.out.println(Thread.currentThread().getName()+"==="+num);
        //Wake up other waiting threads
        this.notifyAll();
    }
}

This is the result of the normal operation of the program:

2, Then I'll show you how to start four threads, two consumer threads and two producer threads

At this time, there are producer A1, producer A2, consumer B1 and consumer B2

package com.aa.Producer consumer model;

public class A {

    public static void main(String[] args) {
        Data data = new Data();

        //Producer thread A1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"producer A1").start();

        //Consumer thread B1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"consumer B1").start();

          new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"producer A2").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"consumer B2").start();

    }


}

//This is the shared area data, which has only one attribute num
class Data{
    private int num=0;

    //Producer pair num++
    public synchronized void increment() throws InterruptedException {


        if(num!=0){
            this.wait();  //At this time, the thread is blocked, so that the thread will continue to execute subsequent code after being awakened, which is why you don't use if while
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==="+num);
        //Wake up other threads
        this.notifyAll();
    }

    //Consumer satisfaction with num--
    public synchronized void decrement() throws InterruptedException {

        if (num==0){
            this.wait();//At this time, the thread is blocked, so that the thread will continue to execute subsequent code after being awakened, which is why you don't use if while
        }

        num--;

        System.out.println(Thread.currentThread().getName()+"==="+num);
        //Wake up other waiting threads
        this.notifyAll();
    }
}

Then let's see the operation effect:
The front operation is normal, but the back is not normal. And there will be an endless cycle. The program runs all the time. This is mainly because the if statement is used. When the thread is blocked, it is suspended. When other threads use notifyAll(), if this thread is executed, the suspended thread will then execute the code behind the wait() method, for num + + or num --. However, if the while is used instead of if, it will always judge whether the current condition is satisfied or not, and then wait() Execution will not continue until the judgment statement of while is not satisfied, and if is executed directly and will not be judged again.

3, Correct producer consumer model

The correct producer consumer code is as follows:

package com.aa.Producer consumer model;

public class A {

    public static void main(String[] args) {
        Data data = new Data();

        //Producer thread A1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"producer A1").start();

        //Consumer thread B1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"consumer B1").start();

          new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"producer A2").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"consumer B2").start();

    }


}

//This is the shared area data, which has only one attribute num
class Data{
    private int num=0;

    //Producer pair num++
    public synchronized void increment() throws InterruptedException {


        while(num!=0){
            this.wait();  //At this time, the thread is blocked, so that the thread will continue to execute subsequent code after being awakened, which is why you don't use if while
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==="+num);
        //Wake up other threads
        this.notifyAll();
    }

    //Consumer satisfaction with num--
    public synchronized void decrement() throws InterruptedException {

        while (num==0){
            this.wait();//At this time, the thread is blocked, so that the thread will continue to execute subsequent code after being awakened, which is why you don't use if while
        }

        num--;

        System.out.println(Thread.currentThread().getName()+"==="+num);
        //Wake up other waiting threads
        this.notifyAll();
    }
}

The effect after the program is run is as follows:

At the beginning, I didn't understand the difference between while and if between producers and consumers. I found it by accident after a long time of failure in school recruitment preparation for an interview with a company. So I wrote quickly to share with you, hoping to help you successfully find your favorite company. It's really difficult to find a job. It's hard to lower your standards again and again, alas! Wish: what you think, success, come on, everyone!!! Rush!!!

Posted by socratesone on Mon, 11 Oct 2021 14:30:22 -0700