• Java多线程生产者消费者模式(二)之死锁与虚假唤醒


    前提:

    当只有一个生产者与消费者,也就是只有两个线程时,唤醒的永远时对方线程。

    当只有一个生产者时和两个消费者,或者两个生产者与两个消费者时,唤醒的就是所有线程了,这样就会产生死锁和虚假唤醒。

    多线程对多线程,必会有死锁和虚假唤醒问题。

    比如下面的代码,初看正常,刚运行几次也正常,但多运行几次就出现问题了。大概率出现的问题是死锁,程序无穷无尽的卡住了。

    我们来理解这个问题:C吃完了包子,此时包子为0个,C唤醒了厨师A和吃货B这两个线程。

    因为A和B都醒了,A作为厨师去生产包子了。

    B作为吃货一看包子为0个,就等着,而且是死等;当厨师A做完包子,唤醒大家去吃包子时,B还在死等,而此时虽然C也被唤醒了。

    但C一看被锁住了,而这个吃货B却死等着不让,于是B和C就僵持住了。

    相当于:餐厅里只有一个位置,B一看没有包子了,就死等;在B死等的时候,厨师A做好了一个包子并叫大家去吃。

    C高兴的去吃包子,但位置被B占用了,而且B不知道厨师做好了包子,一直死等,一直占着位置,这样一来,就卡在B这里了,C和A都急死了。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Bun {
        public static void main(String[] args) {
            SteamedBun bun = new SteamedBun();
    
            new Thread(() -> {
                for (int i = 0; i < 5; i++) {
                    try {
                        bun.produce();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }, "厨师A").start();//定义了一个厨师线程,生长包子
            new Thread(() -> {
    
                for (int i = 0; i < 5; i++) {
                    try {
                        bun.eat();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "吃货B").start();//定义了一个吃货线程,吃包子
    
    
            new Thread(() -> {
    
                for (int i = 0; i < 5; i++) {
                    try {
                        bun.eat();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "吃货C").start();//定义了一个吃货线程,吃包子
    
        }
    }
    
    
    class SteamedBun {
        private int num = 0;//包子数量
    
        //生产者,包子铺的厨师
        public synchronized void produce() throws InterruptedException {
            while (num != 0) {
                this.wait();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "生产了1个包子");
            this.notifyAll();
        }
    
    
        //消费者-->吃包子的吃货
        public synchronized void eat() throws InterruptedException {
            while (num == 0) {
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "吃了1个包子");
            this.notifyAll();
            System.out.println(Thread.currentThread().getName()+"叫厨师去做包子");
        }
    }

    以上代码运行结果偶尔正常,偶尔发生本文开头提到的死锁。

    下面的结果只有14行,就卡在14行不动了。

    厨师A生产了1个包子
    吃货B吃了1个包子
    吃货B叫厨师去做包子
    厨师A生产了1个包子
    吃货B吃了1个包子
    吃货B叫厨师去做包子
    厨师A生产了1个包子
    吃货C吃了1个包子
    吃货C叫厨师去做包子
    厨师A生产了1个包子
    吃货B吃了1个包子
    吃货B叫厨师去做包子
    厨师A生产了1个包子
    吃货C吃了1个包子
    吃货C叫厨师去做包子
  • 相关阅读:
    python基础12-语法
    基础篇-内置函数(常用)
    中级篇-内置函数 (map/filter/reduce)
    python 基础11-递归
    python 基础10-函数、变量
    python 基础9-拼接
    redis
    python--os模块
    函数return多个值
    python--文件读写
  • 原文地址:https://www.cnblogs.com/majestyking/p/12451639.html
Copyright © 2020-2023  润新知