青铜10:千锤百炼-如何解决生产者与消费者经典问题
欢迎来到《并发王者课》,本文是该系列文章中的第10篇。
在本篇文章中,我将为你介绍并发中的经典问题-生产者与消费者问题,并基于前面系列文章的知识点,通过wait、notify实现这一问题的简版方案。
一、生产者与消费者问题
生产者消费者问题(Producer-consumer problem),也称有限缓冲问题(Bounded-buffer problem),是一个多进程、线程同步问题的经典案例。
这个问题描述了共享固定大小缓冲区的两个进程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。
生产者与消费者问题的关键在于要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。
同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用线程间通信的方法解决该问题,常用的方法有信号量等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。
当然,生产者与消费者问题并不是局限于单个生产者与消费者,在实际工作中,遇到更多的是多个生产者和消费者的情形。
生产者与消费者模式在软件开发与设计中有着非常广泛的应用。在这一模式中,生产者与消费者相互独立,它们仅通过缓冲区传递数据,因此可以用于程序间的解耦、异步削峰等。
生产者与消费者问题的要点:
- 生产者与消费者解耦,两者通过缓冲区传递数据;
- 缓冲区数据装满了之后,生产者停止数据生产或丢弃数据;
- 缓冲区数据为空后,消费者停止消费并进入等待状态,等待生产者通知。
二、实现生产者与消费者方案
本节中,我们通过王者中的一个场景来模拟生产者与消费者问题。
在王者中,英雄兰陵王需要通过打野来发育,但是野区的野怪在被打完之后,需要隔一段时间再投放。
所以,我们创建两个线程,一个作为生产者向野区投放野怪,一个作为消费者打怪。
生产者:每秒检查一次野区,如果野区没有野怪,则进行投放。野怪投放后,通知打野英雄。
// 野怪投放【生产者】
public static class WildMonsterProducer implements Runnable {public void run() {try {createWildMonster();} catch (InterruptedException e) {System.out.println("野怪投放被中断");}}//投放野怪,每1秒检查一次public void createWildMonster() throws InterruptedException {for (int i = 0;; i++) {synchronized(wildMonsterArea) {if (wildMonsterArea.size() == 0) {wildMonsterArea.add("野怪" + i);System.out.println(wildMonsterArea.getLast());wildMonsterArea.notify();}}Thread.sleep(1000);}}
}
消费者:打野英雄兰陵王作为消费者,在野区打怪发育。如果野区有野怪,则打掉野怪。 如果没有,会进行等待野区新的野怪产生。
// 兰陵王,打野英雄
public static class LanLingWang implements Runnable {public void run() {try {attackWildMonster();} catch (InterruptedException e) {System.out.println("兰陵王打野被中断");}}// 打野,如果没有则进行等待public void attackWildMonster() throws InterruptedException {while (true) {synchronized(wildMonsterArea) {if (wildMonsterArea.size() == 0) {wildMonsterArea.wait();}String wildMonster = wildMonsterArea.getLast();wildMonsterArea.remove(wildMonster);System.out.println("收获野怪:" + wildMonster);}}}
}
创建野区,并启动生产者与消费者线程。
public class ProducerConsumerProblemDemo {// 野怪活动的野区private static final LinkedList<String> wildMonsterArea = new LinkedList<String>();public static void main(String[] args) {Thread wildMonsterProducerThread = new Thread(new WildMonsterProducer());Thread lanLingWangThread = new Thread(new LanLingWang());wildMonsterProducerThread.start();lanLingWangThread.start();}
}
在上面几段代码中,你需要重点注意的是synchronized
、wait
和notify
用法,它们是本次方案的关键。运行结果如下:
野怪0
收获野怪:野怪0
野怪1
收获野怪:野怪1
野怪2
收获野怪:野怪2
野怪3
收获野怪:野怪3
野怪4
收获野怪:野怪4
野怪5
收获野怪:野怪5
野怪6
收获野怪:野怪6
从结果可以看到,生产者在创建野怪后,打野英雄兰陵王会进行打野,实现了生产者与消费者的问题。
小结
以上就是关于线程异常处理的全部内容,在本文中我们基于wait、notify来解决生产者与消费者问题。对于本文内容,你需要理解生产者与消费者问题的核心是什么。另外,本文所提供的方案仅仅是这一问题多种解决方案中的一种,在后面的文章中,我们会根据新的知识点提供其他的解法。
正文到此结束,恭喜你又上了一颗星✨
夫子的试炼
- 编写代码实现生产者与消费者问题。
延伸阅读
- Producer–consumer problem
- 《并发王者课》大纲与更新进度总览
关于作者
关注公众号【庸人技术笑谈】,获取及时文章更新。记录平凡人的技术故事,分享有品质(尽量)的技术文章,偶尔也聊聊生活和理想。不贩卖焦虑,不做标题党。
如果本文对你有帮助,欢迎点赞、关注、监督,我们一起从青铜到王者。
青铜10:千锤百炼-如何解决生产者与消费者经典问题相关推荐
- 并发王者课-青铜10:千锤百炼-如何解决生产者与消费者经典问题
欢迎来到<并发王者课>,本文是该系列文章中的第10篇. 在本篇文章中,我将为你介绍并发中的经典问题-生产者与消费者问题,并基于前面系列文章的知识点,通过wait.notify实现这一问题的 ...
- blockingdeque java_Java BlockingDeque解决生产者与消费者问题
BlockingDeque解决生产者与消费者问题的代码如下: import java.util.concurrent.BlockingDeque; import java.util.concurren ...
- Linux信号量与互斥锁解决生产者与消费者问题
先来看什么是生产者消费者问题: 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问 ...
- JAVA并发编程 之 LMAX Disruptor使用实例(高效解决生产者与消费者问题)
什么是Disruptor? Disruptor是一个开源的JAVA框架,它被设计用于在生产者-消费者(producer-consumer problem,简称PCP)问题上获得尽量高的吞吐量(TPS) ...
- 操作系统-------用P,V操作解决生产者和消费者问题(详解!!!)
问题: 系统中有一组生产者进程和一组消费者进程,生产者每次生产一个产品放入缓冲区,消费者每次从缓冲区取出一个产品并使用(注:这里的产品可以理解成某种数据). 条件:生产者.消费者共享一 ...
- 【JAVA多线程】如何解决一个生产者与消费者问题
如何解决一个生产者与消费者问题 生产者与消费者问题是多线程同步的一个经典问题.生产者和消费者同时使用一块缓冲区,生产者生产商品放入缓冲区,消费者从缓冲区中取出商品.我们需要保证的是,当缓冲区满时,生产 ...
- 【学习笔记】第二章——管程(解决生产者消费者问题、封装、Java 体现)
填坑系列!立个这几天补完的 Flag 因为这个视频的笔记,很多人都已经写得很好了,所以接下来的博客,只会记录一些 [常考][和 Java 相关][感觉很有必要记录]的内容 文章目录 一. 概念 二. ...
- Python中的生产者与消费者模式(转载)
利用多线程和队列可以实现生产者消费者模式.该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度. 1.什么是生产者和消费者? 在线程世界里,生产者就是生产数据(或者说发布任务)的线程 ...
- python生产和消费模型_python queue和生产者和消费者模型
queue队列 当必须安全地在多个线程之间交换信息时,队列在线程编程中特别有用. classqueue.Queue(maxsize=0) #先入先出classqueue.LifoQueue(maxsi ...
最新文章
- netty tcp 字节有序-gt;对象有序
- 【Paper】2021_Optimal Distributed Leader-following Consensus of Linear Multi-agent Systems: A Dynamic
- JPEG压缩matlab实现
- acme云服务器生成证书_使用 acme.sh 申请 SSL 证书并且定期自动更新
- PHP 设计模式之原型模式
- mysql8出现The MySQL server is running with the --skip-grant-tables option so it cannot execute
- k8s中流量分离以及资源隔离实战
- android qml 菜单,QML - ListView项目,用于显示菜单
- 上传文件到服务器地址怎么配置,文件上传到服务器怎么配置
- 了解 node.js
- 深信服scsa知识点一
- 计算机输入码分类,汉字输入码种类数字编码.ppt
- css 入场动画_进入css3动画世界(一)
- 【039】读典籍-在线阅读典籍并对应翻译
- Go:Comb sort 梳状排序(附完整源码)
- php 表示每月一号,适合每月一号发的说说
- 测试面试题-如何测试朋友圈
- 提速降费再发力 中国联通推出八项惠民便民措施
- 业务数据分析-大体逻辑
- 用自己训练的AI玩王者荣耀是什么体验?
热门文章
- Python 会被取代了?什么时候?
- intel六代/七代CPU不支持win7系统不包含USB3.0驱动/蓝屏/重启
- Linux安装Mysql8.0.23
- 华为云大数据BI,企业数字化运营得力助手
- 基于thymeleaf的页面静态化技术
- 在线帮助你修改图片背景的工具 - Clipping Magic
- Money Pro for Mac(理财应用程序)
- 【f1c200s/f1c100s】mangopi自制linux开发板驱动适配进度(PCB、代码开源)
- centos dnf命令原始源安装mysql成功案例
- 软件工程——程序编码