关于生产者消费者的问题

因为 https://blog.51cto.com/u_3631118/3119794 引发的问题

不去掉else

不去掉else影响的是生产者或者消费者的循环次数,如果二者循环次数不一致,就会导致循环慢的那个因为没有收到notify而处于wait状态,从而导致程序无法停止。

去掉else

如果去掉else,消费者每次都能notify生产者,即使生产者处在wait状态,消费者也能通知到,而上一种情况是有可能不会notify生产者,而生产者此时就在wait状态,也就到这了循环次数不一致的问题,如果消费者每次都能notify生产者,那么即使生产者处在wait状态,消费者也能通知到。这就是二者的不同之处:能够保证生产者处于wait状态,也能有消费者notify到。

以下为有问题的实验源代码,把消费者的else去掉就可以解决问题

package com.atguigu.sync;

/**
 * @author xiu
 * @create 2022-06-04 21:04
 */
public class ThreadDemo1 {
    public static void main(String[] args) {
        Share share = new Share();
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                try {
				    //生产者慢100毫秒,使问题暴露
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                share.add();
            }

        }, "add").start();
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                share.decrease();
            }
        }, "decrease").start();
    }

}

class Share {
    int num = 0;
    int num2;
    int count = 0;

    //线程交替的三个步骤: 1.判断 2.干活 3.通知
//    判断和通知可以互换顺序,因为已经在锁里边,不会被抢走资源
//生产者方法
    public synchronized void add() {
        num2++;
        if (count == 2) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else
            count++;
        System.out.println("增加一个剩余" + count);
        notifyAll();
        System.out.println("生产者次数" + num2);
    }
//消费者方法
    public synchronized void decrease() {
        num++;
        if (count == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**
             * 带有else的情况
             *  去掉else其实就是改变notify的次数,如果notify的次数不够多,生产者总会因为生产满了而卡在wait,导致循环次数变少,而消费者的循环次数不会变少,
             * 就是说消费者循环停止之后生产者还没有结束循环,生产者还没有结束循环就会导致生产者生产满了之后达到wait状态,从而整个程序不能结束
             */

            /**
             * 不带else情况,就是所有情况下都会notify生产者,生产者即使因为生产满了,也会收到notify,此时消费者也会消耗掉,所以生产者不会wait,也就能和消费者配合,最后一起循环结束
             */
        } else {
            count--;
            System.out.println("消耗一个 剩余" + count);
            notifyAll();
            System.out.println("消费者次数" + num);
        }
    }
}
posted @ 2022-06-05 01:05  xiuer211  阅读(40)  评论(0编辑  收藏  举报