生产者消费者模型

生产者和消费者模型:

通过一个容器来解决生产者和消费者的强耦合问题。
生产者消费者彼此之间不直接通讯,而是通过阻塞队列来进行通讯,生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列中里取阻塞队列相当于一个缓冲区,平衡了生产者和消费者的处理能力
阻塞队列就是用来给生产者和消费者解耦的。

线程间通信使用的API:

  1. wait():让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁.
  2. notify():唤醒当前对象上等待的线程(唤醒单个线程)
  3. notifyAll():唤醒所有的线程

这三种方法都是Object类的方法;
先对对象加锁,才能调用上面的三个方法(调用这三个方法必须是在synchronized代码块中)

wait()方法:使线程停止运行。

  1. 使当前线程进行等待。用来及那个当前线程置入"阻塞队列"中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。
  2. wait()方法只能在同步方法中或同步代码块中调用
  3. 如果调用wait()时,没有持有适当的锁,会抛出异常。
  4. wait()方法执行后,当前线程释放锁,线程与其他线程竞争重新获取锁。

notify()方法:使停止的线程继续运行

  1. 用来通知那些可能等待该对象的对象锁的其他线程,对其发出notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则由线程规划器随机挑选出一个呈wait状态的线程。
  2. 在notify()后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,退出同步代码块之后才会释放对象锁。

notifyAll():唤醒所有等待线程

线程间通信的过程:
在这里插入图片描述

消费者一直消费
生产者一直生产
20个消费者线程,消费者每次消费一个
10个生产者线程,生产者每次生产三个
最大库存为100

public class BreadShop1 {
    private static  int COUNT;//表示库存数,线程共享的
    //消费者
    public static class Consumer implements  Runnable{
        private  String  name;

        public Consumer(String name) {
            this.name = name;
        }
        @Override
        public void run() {
            try {
                //一直消费
                while (true){
                    synchronized (BreadShop1.class) {//加同一把锁(消费者和生产者使用的是同一把锁)
                        //库存到达下限,不能继续消费,需要阻塞等待
                        if (COUNT == 0){

                            BreadShop1.class.wait();//库存数等于0,当前线程阻塞等待,释放对象锁
                        }else{
                            //库存> 0,允许消费
                            System.out.printf("消费者 %s 消费了1个面包\n",name);
                            COUNT--;
                            //通知BreadShop1.class.wait();代码进入阻塞的线程
                            BreadShop1.class.notifyAll();//唤醒进入阻塞队列的线程
                            //模拟线程的耗时
                           // Thread.sleep(100);
                        }
                        //优化
                        Thread.sleep(100);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //生产者
    public static  class  Producer implements  Runnable{
        private  String  name;

        public Producer(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                while (true){
                    synchronized (BreadShop1.class) {
                        //库存到达上限
                        if (COUNT + 3 > 100){
                            //到了最大库存数,阻塞
                            BreadShop1.class.wait();//释放对象锁
                        }else{
                            System.out.printf("生产者 %s 生产了3个面包\n",name);
                            COUNT = COUNT +3;
                            BreadShop1.class.notifyAll();
                        }
                    }
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        //模拟20个消费者线程,同时启动20个消费者线程
        Thread[] consumer = new Thread[20];
        for (int i =0;i< 20;i++){
            consumer[i] = new Thread(new Consumer(String.valueOf(i)));
        }
        for (Thread thread : consumer){
            thread.start();
        }

        //模拟10个生产者线程,同时启动10个生产者线程
        Thread[] producers = new Thread[10];
        for (int i =0;i< 10;i++){
            producers[i] = new Thread(new Producer(String.valueOf(i)));
        }

        for (Thread thread : producers){
            thread.start();
        }
    }
}

改变需求:
10个消费者,每次消费的数量为5
5个生产者,每天的生产次数是10,每次生产的个数是3
最大库存量为100

public class BreadShop进阶版 {

    private static int 消费者数量 = 10;
  
    private static int 每次消费的面包数 = 5;
   
    private static int 生产者数量 = 5;
    
    private static int 生产次数 = 10;

    private static int 每次生产的面包数 = 3;
   
    private static int 最大库存数 = 100;
    
    private static int 面包店库存;

    private static int 生产面包的总数;


    public static class Consumer implements Runnable{

        private String name;

        public Consumer(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            //一直消费
            try {
                while (true){
                    synchronized (BreadShop进阶版.class){
                        if(生产面包的总数 == 生产者数量 * 生产次数 * 每次生产的面包数){
                            break;
                        }
                        //库存到达下限,不能继续消费,需要阻塞等待
                        if(面包店库存 - 每次消费的面包数 < 0){
                            BreadShop进阶版.class.wait();//释放对象锁
                        }else {
                            //库存满足消费条件,允许消费
                            面包店库存 -= 每次消费的面包数;
                            System.out.printf("消费者 %s 消费了%s个面包, 库存%s\n", name, 每次消费的面包数, 面包店库存);
                            //通知BreadShop.class.wait();代码进入阻塞的线程
                            BreadShop进阶版.class.notifyAll();
                            //模拟消费的耗时
                            Thread.sleep(200);
                        }
                    }
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //生产者
    public static class Producer implements Runnable{

        private String name;

        public Producer(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                //达到生产次数,满足生产次数才会退出
                for (int i = 0; i< 生产次数; i++){
                    synchronized (BreadShop进阶版.class){
                        //库存到达上限,不能继续生产,需要阻塞等待
                        while(面包店库存 + 每次生产的面包数 > 最大库存数){
                            BreadShop进阶版.class.wait();//释放对象锁
                        }
                        面包店库存 += 每次生产的面包数;
                        生产面包的总数 += 每次生产的面包数;//生产面包的总数要更改
                        //库存满足生产条件
                        System.out.printf("生产者 %s 生产了%s次, 库存%s, 生产的数量%s\n", name, i+1, 面包店库存, 生产面包的总数);
                        //通知BreadShop.class.wait();代码进入阻塞的线程
                        BreadShop进阶版.class.notifyAll();
                        //模拟消费的耗时
                        Thread.sleep(200);
                    }
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        //同时启动消费者线程
        Thread[] consumers = new Thread[消费者数量];
        for(int i = 0; i< 消费者数量; i++){
            consumers[i] = new Thread(new Consumer(String.valueOf(i)));
        }
        //同时启动生产者线程
        Thread[] producers = new Thread[生产者数量];
        for(int i = 0; i< 生产者数量; i++){
            producers[i] = new Thread(new Producer(String.valueOf(i)));
        }

        for(Thread t : consumers){
            t.start();
        }
        for(Thread t : producers){
            t.start();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值