目标:实现在厨师做完20碗饭后,吃货吃一次,厨师做一次。以此达到20碗饭的动态平衡。

(1)厨师类:
package Test.ProducerAndCustomer;

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//目标:复刻黑马程序员的厨师吃货Demo:
    //厨师线程,吃货线程,list代表仓库,0代表没面条,1代表有面条
    public class Producer implements Runnable{
        Object object = Main.object;
    @Override
    public void run() {
        while (true){
            synchronized (object) {


                if (Main.NoodleNum >= 20) {
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    Main.NoodleNum++;
                    System.out.println("厨师已经做了" + Main.NoodleNum + "碗面条!");
                    //叫醒吃货
                    object.notifyAll();

                }
            }
        }
    }
}

(2)吃货类:
package Test.ProducerAndCustomer;


public class Customer implements Runnable{
    @Override
    public void run() {
        Object object = Main.object;
        while (true){

            synchronized (object) {
                if (Main.NoodleNum < 20) {
                    //唤醒厨师继续做:
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                } else {
                    Main.NoodleNum--;
                    System.out.println("吃货现在吃了一碗面!");
                    object.notifyAll();
                }
            }
        }
    }
}

(3)主函数类:
package Test.ProducerAndCustomer;

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    static int NoodleNum = 0;

    static Object object = new Object();

    public static void main(String[] args) {
        Customer customer = new Customer();
        Producer producer = new Producer();
        Thread thCus = new Thread(customer,"吃货");
        Thread thPro = new Thread(producer,"厨师");
        thPro.start();
        thCus.start();
    }
}

最终运行效果:

在这里插入图片描述
注意:代码逻辑不难,主要在于把控notifyAll()wait() 的动作时机,否则会出现,两个线程都进入等待状态却无人唤醒,导致程序卡死。

犯错点:

在确定同步代码块之前,尝试使用ReentrantLock的实例对象来给代码块加锁。在用这个实例对象调用.lock()/.unlock()方法后,又用它来调用wait(),notify()的方法。导致报出IlegalMonitorStateException的错误

这个错误的源头就是,使用lock()/unlock()等方法后又调用wait()/notify()。
因为后两者是隐式锁,而前两者是显式锁,正确的使用方式应该是使用synchronized()和wait(),notify()来搭配调用。

疑惑:

问:为什么synchronized和wait()/notify()的锁对象需要一致?
答:因为这是java对于线程通信的一种设计,如果前后不一致,则IDEA会如此说:
在这里插入图片描述
当前线程不是(锁的)拥有者。这也就表明,一个线程必须要先持有锁,才能进行wait()/notify()的操作。

联想:

1.如果想要套换到飞机大战的应用场景中,则会是 “保持屏幕当中的飞机数量为20,被打掉或者移出屏幕就会自动补全” 的效果。那到时候,上述代码中的NoodleNum就替换成敌机集合list“厨师”则被替换成生成敌机的代码吃货则被替换成我方飞机,而飞机的减少与补齐的行为则对应上述代码的对NoodelNum的增减操作,无非就是add()/remove()方法的套换。
2.在当今的社会生活中,生产者消费模型作为一种原理性的东西,首先会被应用到消息队列,在此基础上,订单_平台数据采集_处理系统图片视频处理日志处理系统,无处不在,体现出它的广泛性。

生产者消费者模型的特点:

1.解耦性:生产者消费者彼此互不相识,互不干扰,彼此只关心并各自操作共用的那部分。
2.错误隔离:生产者出故障不影响消费者处理已有数据,消费者故障不影响生产者产生数据

食客(消费者)今天没来不代表厨师(生产者)今天不会做饭了,厨师今天打样不代表食客没地方吃饭

3.异步性:生产者和消费者的行为不具有强烈的顺序性和关联性,自由度高。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐