生产者和消费者案例

1.案例描述

这里以吃饭为例,假设有一个桌子,用来存汉堡包,然后有厨师和消费者,厨师往桌子上放汉堡包,消费者从桌子上取走汉堡包。当两者在一个时间段同时进行多次自己的操作时,很明显这就是多线程编程的生产者消费者实例了。在这里,我们希望厨师每次生产一个汉堡包,消费者就拿走一个汉堡包,如果汉堡包还没有被取走,那么厨师应该等待,而如果桌子上没有汉堡包,则消费者应该等待。

2.案例分析

厨师类(Cooker):实现Runnable接口【通用】,包含放汉堡包的方法
消费者类(Foodie):实现Runnable接口【通用】,包含拿汉堡包的方法
桌子类(Desk):共享数据
生产者消费者线程套路:
//1. while(true)死循环
//2. synchronized锁,锁对象要唯一
//3.判断,共享数据是否结束.[true]结束
//4.判断,共享数据是否结束,[false]没有结束

测试类(Demo1):测试类按如下步骤实现这个案例
(1) 创建桌子对象作为共享数据区域
(2) 创建厨师线程,把桌子对象作为参数传递至构造方法【需创建对应的桌子对象成员变量】,因为厨师需要完成放汉堡包的操作
(3)创建消费者线程,把桌子对象作为对象传递至构造方法【需创建对应的桌子对象成员变量】,因为消费者需要完成拿汉堡包的操作
(4)启动线程

3.代码实现

<1>等待唤醒实现
wait(); :【等待】
notifyAll() :【叫醒等待的所有线程】

public class Demo1 {public static void main(String[] args) {Desk desk = new Desk();Foodie foodie = new Foodie(desk);foodie.start();Cooker cooker = new Cooker(desk);cooker.start();}
}//厨师类
public class Cooker extends Thread {private Desk desk;public Cooker(Desk desk) {this.desk = desk;}@Overridepublic void run() {//生产者步骤:while (true) {//同步代码块synchronized (desk.getLock()) {//判断汉堡包的数量是否达到if (desk.getCount() == 0) {break;} else {//1,判断桌子上是否有汉堡包if (!desk.isFlag()) {//3.如果没有才生产System.out.println("生产者生产汉堡包");// 把汉堡包放在桌上desk.setFlag(true);//叫醒等待的消费者开吃desk.getLock().notifyAll();} else {//2.如果有就等待try {//使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法desk.getLock().wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}
}//消费者类
public class Foodie extends Thread {private Desk desk;public Foodie(Desk desk) {this.desk = desk;}//消费者步骤:@Overridepublic void run() {while (true) {//同步代码块synchronized (desk.getLock()) {//判断汉堡包的数量if (desk.getCount() == 0) {break;} else { //1,判断桌子上是否有汉堡包if (desk.isFlag()) {//3,如果有就开吃System.out.println("吃货吃汉堡包");//4,吃完之后,桌子上的汉堡包就没有了//叫醒等待的生产者继续生产汉堡包的总数量减一desk.setCount(desk.getCount() - 1);desk.setFlag(false);desk.getLock().notifyAll();//叫醒等待的所有线程[把生产者唤醒]} else {//2,如果没有就等待//没有就等待[释放锁再等待]//使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法try {desk.getLock().wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}
}//桌子类
public class Desk {//定义一个标记//true表示有,false表示没有汉堡包//public static boolean flag;private boolean flag;//定义一个汉堡包数,表示消费几个结束//public static int count = 10;private  int count;//定义一个锁对象 用于消费者线程和生产者线程用同一把锁//public static final Object lock =new Object();private final Object lock =new Object();public Desk(boolean flag, int count) {this.flag = flag;this.count = count;}public Desk() {//无参构造可用于初始化赋值this(false,3);}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public Object getLock() {return lock;}
}打印结果:
----------------------------------------------------------------------
生产者生产汉堡包
吃货吃汉堡包
生产者生产汉堡包
吃货吃汉堡包
生产者生产汉堡包
吃货吃汉堡包

<2>阻塞队列实现
创建阻塞队列实现对象,泛型为String[汉堡包],capacity[队列限量]–1[生产一个拿一个]
原理:阻塞队列的put和take方法内部有锁

//测试类
public class Demo1 {public static void main(String[] args) {//创建阻塞队列实现对象,泛型为String[汉堡包],capacity[队列限量]--1[生产一个拿一个]ArrayBlockingQueue<String> list = new ArrayBlockingQueue<String>(1);Cooker cooker = new Cooker(list);Foodie foodie = new Foodie(list);new Thread(cooker).start();new Thread(foodie).start();//由于阻塞队列的put和take方法内部有锁,// 而我们加上的打印语句不在锁内,所以打印出来不均匀}
}//厨师类
public class Cooker extends Desk implements Runnable {private  ArrayBlockingQueue<String> list;public Cooker(ArrayBlockingQueue<String> list) {this.list =list;}@Overridepublic void run() {while (true){//判断汉堡数if(Desk.count==0){break;}//队列没有则生产try {list.put("汉堡包");//添加元素,添加满了则等待System.out.println("生产者生产了一个汉堡包");} catch (InterruptedException e) {e.printStackTrace();}}}
}//消费者类
public class Foodie extends Desk implements Runnable {private ArrayBlockingQueue<String> list;public Foodie(ArrayBlockingQueue<String> list) {this.list = list;}@Overridepublic void run() {while (true) {//判断汉堡数if(Desk.count==0){break;}//队列有则取出try {String s = list.take();//取出元素,取完了则等待Desk.count--;System.out.println("消费者拿出了" + s);} catch (InterruptedException e) {e.printStackTrace();}}}
}//桌子类
public class Desk {static int count =3;
}打印结果:
----------------------------------------------------------------------
生产者生产了一个汉堡包
生产者生产了一个汉堡包
消费者拿出了汉堡包
消费者拿出了汉堡包
生产者生产了一个汉堡包
消费者拿出了汉堡包

注:【因为阻塞队列有锁,锁会强制线程获取最新共享数据,则不会出现共享数据问题】
【阻塞队列的锁在内部,我们加上的打印语句不在锁内,所以打印出来不均匀】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Python开始机器学习(4:KNN分类算法)

转自&#xff1a; http://blog.csdn.net/lsldd/article/details/41357931 1、KNN分类算法 KNN分类算法&#xff08;K-Nearest-Neighbors Classification&#xff09;&#xff0c;又叫K近邻算法&#xff0c;是一个概念极其简单&#xff0c;而分类效果又很优秀的分类算法。 他的…

Mybatis传递多个参数的4种方式

转载自 Mybatis传递多个参数的4种方式&#xff08;干货&#xff09;现在大多项目都是使用Mybatis了&#xff0c;但也有些公司使用Hibernate。使用Mybatis最大的特性就是sql需要自己写&#xff0c;而写sql就需要传递多个参数。面对各种复杂的业务场景&#xff0c;传递参数也是一…

多线程安全问题2

1.volatile关键字 <1>作用&#xff1a;强制线程每次在使用的时候,都会看一下共享区域最新的值[用于提供线程安全] <2>与synchronized的区别和联系&#xff1a; 把代码块声明为 synchronized&#xff0c;有两个重要后果&#xff0c;通常是指该代码具有 原子性&…

Maven Optional Exclusions使用区别

转载自 Maven Optional & Exclusions使用区别 Optional和Exclusions都是用来排除jar包依赖使用的&#xff0c;两者在使用上却是相反。 Optional定义后&#xff0c;该依赖只能在本项目中传递&#xff0c;不会传递到引用该项目的父项目中&#xff0c;父项目需要主动引用该依赖…

为什么jdk的CLASSPATH环境变量需要设置rt.jar 和 tools.jar

How Classes are Found 中有说明&#xff1a;&#xff08;java启动类文件在 rt.jar中&#xff0c; 而 工具类文件在 tools.jar 中&#xff09; How the Java Launcher Finds Classes The Java launcher, java, initiates the Java virtual machine. The virtual machine searc…

线程池的实现

1.创建线程池 API提供了一个工具类叫Executors&#xff0c;可以用它的方法生成不同特点的线程池&#xff0c;返回一个ExecutorService对象。 <1>Executors.newCachedThreadPool() 【池子中默认是空的&#xff0c;最多可以容纳int类型的最大值】 <3>Executors.new…

JSON Web Token (JWT),服务端信息传输安全解决方案

转载自 JSON Web Token (JWT)&#xff0c;服务端信息传输安全解决方案JWT介绍 JSON Web Token(JWT)是一种开放标准(RFC 7519)&#xff0c;它定义了一种紧凑独立的基于JSON对象在各方之间安全地传输信息的方式。这些信息可以被验证和信任&#xff0c;因为它是数字签名的。JWTs可…

thinking-in-java(18) java io

【0】README&#xff1a;本篇文章是以 thinking in java 为基础梳理的&#xff1b; 【18.1.1 目录列表器】 // 传入正则表达式以过滤文件名如 (.*src)* public class DirList {public static void main(String[] args) {File path new File(".");String[] list; i…

并发工具类【线程安全相关的类】

1.Hashtable和ConcurrentHashMap Hashtable&#xff1a;哈希表结构&#xff08;数组链表&#xff09;&#xff0c;线程安全的(同步代码块&#xff0c;效率低) ConcurrentHashMap&#xff1a; jdk7:采用Segment数组[不会扩容] HashEntry[二次哈希计算存入的位置,可扩容]&#…

JSON Web Token (JWT)生成Token及解密实战

转载自 JSON Web Token (JWT)生成Token及解密实战昨天讲解了JWT的介绍、应用场景、优点及注意事项等&#xff0c;今天来个JWT具体的使用实践吧。从JWT官网支持的类库来看&#xff0c;jjwt是Java支持的算法中最全的&#xff0c;推荐使用&#xff0c;网址如下。https://github.co…

java中两个map的融合(两个map有相同字段)

试想这样一个场景&#xff1a; 数据库表中 有 城市信息表 city_tbl&#xff1b; 有院士信息表 ys_tbl &#xff0c;其中院士有城市id字段&#xff08;id&#xff09;&#xff1b; 但是不是所有城市都有院士&#xff1b; 我们想要得到 城市的详细信息&#xff0c;包括院士个数…

网络编程实现

1.网络编程三要素 1.IP地址&#xff1a;网络中设备的唯一标识IPv4: 由4个字节组成&#xff0c;点分十进制表示法IPv6: 由16个字节组成&#xff0c;冒分十六进制表示法"127.0.0.1"本地主机网络地址【用于测试】相关命令&#xff1a;ipconfig: 查看本机在当前网络环境…

通用唯一标识码UUID的介绍及使用

转载自 通用唯一标识码UUID的介绍及使用。什么是UUID&#xff1f; UUID全称&#xff1a;Universally Unique Identifier&#xff0c;即通用唯一识别码。 UUID是由一组32位数的16进制数字所构成&#xff0c;是故UUID理论上的总数为16^32 2^128&#xff0c;约等于3.4 x 10^38。也…

IEEE论文检测的字体未嵌入问题Times New Roman,Bold, Times New Roman,Italic is not embedded解决方法

【1】README 毕业前写了一篇 英文paper&#xff0c; 接受后&#xff0c;需要提交到 IEEE PDF Express 做格式检测&#xff1b;&#xff1b;latex源码中引用了 Visio生成的算法流程图&#xff0c;PDF文件&#xff1b; 谁料&#xff0c;哥子提交上去后&#xff0c;报如下错误&…

类加载器的创建

1.什么是类加载器 <1>概念&#xff1a;类加载器是用来加载类的工具(从硬盘加载到JVM内存) <2>类加载器的加载时机【类在使用时才被加载&#xff0c;不使用不加载】 a.创建类的对象时 b.通过类名调用静态方法时 c.通过反射加载类 <3>3.类加载器的分类 a.启动…

Java 必看的 Spring 知识汇总

转载自 Java 必看的 Spring 知识汇总Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而&#xff0c;Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性的角度而言&#xff0c;绝大部分Java应用…

Java 截取反斜杠--java使用split拆分特殊字符

orgn link : http://blog.csdn.net/scy411082514/article/details/7987852 Java 截取反斜杠 replaceAll和split &#xff08;“\”&#xff09; 问题解决办法 2009年07月15日 星期三 上午 11:26 xxx.split("\\") 显然得不到想要的结果 正确方法 xxx.split(&qu…

反射的实现

1.获取类的字节码对象 //获取类的字节码对象 public class Demo1 {public static void main(String[] args) throws ClassNotFoundException {//方式1&#xff1a;类名.ClassClass<?> clazz1 Student.class;//方式2&#xff1a;对象名.getClass()Student student new…

thinking-in-java(11) 持有对象

【11.1】泛型和类型安全的容器 &#xff08;1&#xff09;ArrayList<Apple> 中尖括号括起来的是&#xff1a; 类型参数&#xff0c;它指定了这个容器实例可以保存的类型&#xff1b; 【荔枝&#xff1a;有泛型和没有泛型的区别】 class Apple {private static long coun…

JDK9新特性实战:简化流关闭新姿势

转载自 JDK9新特性实战&#xff1a;简化流关闭新姿势。做Java开发的都知道&#xff0c;每个资源的打开都需要对应的关闭操作&#xff0c;不然就会使资源一直占用而造成资源浪费&#xff0c;从而降低系统性能。 关于资源的关闭操作&#xff0c;从JDK7-JDK9有了不少的提升及简化。…