首页 > 其他分享 >生产者和消费者模式

生产者和消费者模式

时间:2023-02-21 02:11:38浏览次数:21  
标签:消费者 Thread 生产者 模式 queue 队列 线程 new 出餐

生产者消费者模式(简易版)

  • synchronize 中的 wait 和 notifyAll 实现

    • synchronize: 当一个线程进入到同步代码块时,会获取到当前的锁,而这时如果其他使用同样的锁的同步代码块也想执行内容,就必须等待当前同步代码块的内容执行完毕,在执行完毕后会自动释放这把锁,而其他的线程才能拿到这把锁并开始执行同步代码块里面的内容
  • 生产者和消费者中间需要有"一条通道"来进行取和产的存放, 因此会用到数据结构的"队列",队列拥有先进先出的特性

  • 队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作


生产者模式

  • 代入厨师的生产模式:生产菜品需要时间,利用Thread.sleep方法进行睡眠(假设做菜时间)
  • 利用synchronized是"谁拿到这个锁谁就可以运行它所控制的那段代码"
    private static void Producer() {
        while (true) {
            try {
                Thread.sleep(3000);
                synchronized (queue){
                    String name = Thread.currentThread().getName();//获取线程名字
                    System.out.println(new Date() + " "+ name+" 出餐了!!!");
                    queue.offer(new Object());//增加菜品进队列
                    queue.notifyAll();//不止有一个客户队列
//唤醒queue.wait的线程, 通知队列客户可以取餐
//因为有好几个客户线程,几个客户线程的队列都可能为空然后被wait,所以需要唤醒几个客户线程的队列
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

消费者模式

  • 代入客户的消费模式:客户取走餐并享用,需要Thread.sleep方法进行睡眠(假设吃饭的时间),sleep需要在"取餐代码"后面(可理解为取走队列中的菜品后才可以sleep享用)
  • 利用synchronized是"谁拿到这个锁谁就可以运行它所控制的那段代码
private static void Consumer() {
        while(true) {
            try {
                synchronized (queue){
                    while (queue.isEmpty()) {queue.wait();}
//需要使用while来不断循环判断队列中是否有菜, 只用if只会判断一次,队列中有可能会有很多菜品
                    queue.poll();
                    String name = Thread.currentThread().getName();//获取线程名字
                    System.out.println(new Date() + " "+ name+" 取走了餐 正在享用!!!");
                }
                Thread.sleep(6000);//取走需要享用的等待时间
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

生产者消费者模式代码(无限循环式)

  • 需要自身停止

image

package ConsumerProduce;//注意自身的包名

import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;

public class ConsumerProduce {
    private static Queue<Object> queue = new LinkedList<>();//基于链表创建队列数据结构
    public static void main(String[] args) {
        new Thread(ConsumerProduce::Producer, "chef.1").start();
        new Thread(ConsumerProduce::Producer, "chef.2").start();

        new Thread(ConsumerProduce::Consumer, "client.1").start();
        new Thread(ConsumerProduce::Consumer, "client.2").start();
    }

    private static void Producer() {
        while (true) {
            try {
                Thread.sleep(3000);
                synchronized (queue){
                    String name = Thread.currentThread().getName();//获取线程名字
                    System.out.println(new Date() + " "+ name+" 出餐了!!!");
                    queue.offer(new Object());
                    queue.notifyAll();
                    //唤醒queue.wait的线程, 通知队列客户可以取餐
                    //因为有好几个客户线程,几个客户线程的队列都可能为空然后被wait,所以需要唤醒几个客户线程的队列
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static void Consumer() {
        while(true) {
            try {
                synchronized (queue){
                    while (queue.isEmpty()) {queue.wait();}
                    //需要使用while来不断循环判断队列中是否有菜, 只用if只会判断一次,队列中有可能会有很多菜品
                    queue.poll();
                    String name = Thread.currentThread().getName();
                    System.out.println(new Date() + " " + name +" 取走了餐 正在享用!!!");
                }
                Thread.sleep(6000);//取走需要享用的等待时间
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


注意

  1. 需要注意synchronized的使用; 例如上述代码, 谁获取了queue对象的锁谁就可以运行它所控制的那段代码

  2. 使用的是基于链表创建的队列, 理解为链表样式的队列结构;需要对数据结构队列有一定认识;如offer和poll的操作


代码解析

image

1: chef.1在14s出餐了(需要3s后(17s)才可出餐)

2: client.2在14s取走了(需要6s后(20s)才可以再取餐)

3: chef.2在14s出餐了(需要3s后(17s)才可出餐)

4: client.1在在14s取走了(需要6s后(20s)才可以再取餐)

5: chef.1在17s出餐了(需要3s后(20s)才可出餐)

6: chef.2在17s出餐了(需要3s后(20s)才可出餐)

7: client.1在在20s取走了(需要6s后(26s)才可以再取餐)

8: client.2在在20s取走了(需要6s后(26s)才可以再取餐)

9: chef.1在20s出餐了(需要3s后(23s)才可出餐)

10: chef.2在20s出餐了(需要3s后(23s)才可出餐)

11: chef.2在23s出餐了(需要3s后(26s)才可出餐)

12: chef.2在23s出餐了(需要3s后(26s)才可出餐)

  • chef.1和chef.2各连续出餐两次,并没有client取餐; 原因正是client正在享用(6s进食)

  • 最后两行client.1和client.2都是于26s取走菜品


标签:消费者,Thread,生产者,模式,queue,队列,线程,new,出餐
From: https://www.cnblogs.com/WoOD-outPut/p/17139552.html

相关文章

  • CSS文本,字体设置与元素显示模式
    什么是元素的显示模式网页中的标签很多,在不同的地方使用不同类型的标签。元素显示模式就是标签以什么方式进行显示。如:div自己占一行,span一行可以放多个。HTML元素一般......
  • spark-3.3.2-bin-hadoop3-scala2.13 Local模式
    目标搭建单机开发环境,执行pyspark程序安装Anaconda3-2022.10-Linux-x86_64.sh安装pycharm-community-2022.3.2.tar.gz 环境OS:Ubuntu22基础包安......
  • 高级程序员解决问题的思维模式
    「NLP理解层次」将对一件事的理解,由低到高分为6个不同的层次,即维度。低维角度无法解决的问题,站在更高的维度理解,就会称为一个非常简单的问题,我愿称之为「降维打击」。接下来......
  • KVM虚拟化之磁盘:磁盘缓存模式
     虚拟化一般网络和存储都是难点。下图所示,磁盘I/O从虚拟机到宿主物理机存储的过程。其中虚拟机镜像并不是必须的。并不一定要给虚拟机创建虚拟磁盘文件。我们可以通过逻......
  • redis集群模式
    以前的redis要搞几个节点,每个节点存储一部分的数据,得借助一些中间件来实现,比如说有codis、twemproxy,有一些redis中间件,你读写redis中间件,redis中间件负责将你的数据分布......
  • 华为云API Arts:用“1+1+5”的模式,为你带来API-First体验
    摘要:华为云APIArts是API全生命周期一体化协作平台,支持开发者一站式高效实现API设计、API开发、API测试、API托管、API运维、API变现,助力企业数字化转型。本文分享自华为......
  • 什么是前后端分离开发模式?
    随着数字化管理越来越规范化,低代码开发平台也获得了市场的喜爱。在信息化爆炸式发展的当下,不少低代码开发者也看到了前后端分离开发模式带来的优势特点,于是纷纷加入研发阵......
  • CSS架构之BEM设计模式
    为什么需要CSS架构?其实在日常开发CSS当中,会遇到许多的问题,使用设计模式能够很好的解决。例如在日常开发项目,需要组件化时,组件内部的class样式类管理就非常的杂乱。大部分公......
  • 项目一众筹网03_5_工作模式探讨同步和异步探讨
    系列文章目录文章目录​​系列文章目录​​​​22-Ajax工作模式探讨-异步​​​​23-Ajax工作模式探讨-同步​​​​24-Ajax工作模型探讨-总结​​一般我们开发的程序都是......
  • 通信小白基础学习---MIMO技术入门,含码字,层映射,天线端口,预编码,PMI,rank,TM模式,波束赋形,空
    以下内容来源于B站up主“捻叶成剑”,如有侵权,请联系本人删除!载波聚合技术是增加带宽(拓宽车道),2*2MIMO是增加天线(增加车道为双车道)还有空分多址(实际应用不多)接收两......