生产者消费者模式为什么不用if语句而用while循环

一、生产者消费者模式(只有两个线程一个是生产者线程一个是消费者线程)

重点!!!!!!!看这篇博客的时候首先要描述一下wait()方法的等待机制,当当先线程被wait之后会释放锁,当这个线程被唤醒的时候会继续从wait方法后面的代码继续执行。这个点也是这篇文章的点睛之笔,重中之重。也是为什么不用if用while的原因。

小声bb:我也是翻阅好多文章才知道线程阻塞,被唤醒之后竟然会接着执行线程wait方法后面的代码。我原来竟然一直傻逼的认为这个线程被阻塞之后会重新执行。菜鸟就是我我就是彩笔。

首先看一下只有一个生产者和线程一个消费者线程的情况,这个时候使用if(多个生产者和消费者线程的时候一定要使用while,下面会接着描述)不会出现数据错误,因为只有两个线程调用this.notifyAll()的时候只会唤醒所有的线程,但是这个时候只有一个等待线程。代码如下:

package com.aa.生产者消费者模式;

public class A {

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

        //生产者线程A1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"生产者A1").start();

        //消费者线程B1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"消费者B1").start();

    }


}

//这是是共享区域data,里面只有一个属性num
class Data{
    private int num=0;

    //生产者对 num++
    public synchronized void increment() throws InterruptedException {
        
        //我是故意用if的,在这里不会出错,因为只有两个线程,被唤醒的只能是消费者线程,对num--
        if(num!=0){
            this.wait();  //此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==="+num);
        //唤醒其他线程
        this.notifyAll();
    }

    //消费者对 num--
    public synchronized void decrement() throws InterruptedException {

        //我是故意用if的,在这里不会出错,因为只有两个线程,被唤醒的只能是生产者线程
        if (num==0){
            this.wait();//此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
        }

        num--;

        System.out.println(Thread.currentThread().getName()+"==="+num);
        //唤醒其他等待的线程
        this.notifyAll();
    }
}

这个是程序正常运行的结果:
生产者消费者模式为什么不用if语句而用while循环

二、然后给大家演示一下开始四个线程,两个消费者线程两个生产者线程

此时有生产者A1,生产者A2,消费者B1,消费者B2

package com.aa.生产者消费者模式;

public class A {

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

        //生产者线程A1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"生产者A1").start();

        //消费者线程B1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"消费者B1").start();

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

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

    }


}

//这是是共享区域data,里面只有一个属性num
class Data{
    private int num=0;

    //生产者对 num++
    public synchronized void increment() throws InterruptedException {


        if(num!=0){
            this.wait();  //此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==="+num);
        //唤醒其他线程
        this.notifyAll();
    }

    //消费者对 num--
    public synchronized void decrement() throws InterruptedException {

        if (num==0){
            this.wait();//此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
        }

        num--;

        System.out.println(Thread.currentThread().getName()+"==="+num);
        //唤醒其他等待的线程
        this.notifyAll();
    }
}

然后给大家看一下运行效果:
生产者消费者模式为什么不用if语句而用while循环前面运行还算正常,后面就不正常了。而且会出现死循环。程序一直运行。主要就是因为使用了if语句当线程阻塞后,被挂起,当其他线程使用notifyAll()之后,假如这个线程被执行了,这个被挂起的线程会接着执行wait()方法后面的代码,对num++或者num--,但是如果使用while替代if之后他会一直判断当前条件满不满足不满足接着被wait()直至不满足while的判断语句时之后才会继续执行,而if是直接执行不会再次进行判断。

三、正确的生产者消费者模式

正确的生产者消费者代码如下:

package com.aa.生产者消费者模式;

public class A {

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

        //生产者线程A1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"生产者A1").start();

        //消费者线程B1
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"消费者B1").start();

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

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

    }


}

//这是是共享区域data,里面只有一个属性num
class Data{
    private int num=0;

    //生产者对 num++
    public synchronized void increment() throws InterruptedException {


        while(num!=0){
            this.wait();  //此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==="+num);
        //唤醒其他线程
        this.notifyAll();
    }

    //消费者对 num--
    public synchronized void decrement() throws InterruptedException {

        while (num==0){
            this.wait();//此时线程阻塞,让线程被唤醒之后会重新继续执行后续代码,这也是为什么不用if用while的原因
        }

        num--;

        System.out.println(Thread.currentThread().getName()+"==="+num);
        //唤醒其他等待的线程
        this.notifyAll();
    }
}

程序运行之后的效果如下:
生产者消费者模式为什么不用if语句而用while循环
我刚开始也是不理解while和if在生产者和消费者之间的区别,我也是在经历校招准备面试某公司很长时间失败之后,才偶然发现的。于是奋笔疾书给大家分享一下,希望能够帮助大家顺利找到心仪的公司,小声bb菜鸡找工作真难,一次一次降低自己的标准,唉!愿:心所想,有所成,加油各位!!!冲!!!

上一篇:阻塞队列


下一篇:Atom 和 VSCode 同一天发布神器:实时编码分享