生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。

这里实现如下情况的生产--消费模型:

生产者不断交替地生产两组数据“姓名--1 --> 内容--1”,“姓名--2--> 内容--2”,消费者不断交替地取得这两组数据,这里的“姓名--1”和“姓名--2”模拟为数据的名称,“内容--1 ”和“内容--2 ”模拟为数据的内容。

由于本程序中牵扯到线程运行的不确定性,因此可能会出现以下问题:

1、假设生产者线程刚向数据存储空间添加了数据的名称,还没有加入该信息的内容,程序就切换到了消费者线程,消费者线程将把信息的名称和上一个信息的内容联系在一起;

2、生产者生产了若干次数据,消费者才开始取数据,或者是,消费者取完一次数据后,还没等生产者放入新的数据,又重复取出了已取过的数据。

问题1很明显要靠同步来解决,问题2则需要线程间通信,生产者线程放入数据后,通知消费者线程取出数据,消费者线程取出数据后,通知生产者线程生产数据,这里用wait/notify机制来实现。

代码如下:

  1. package com.itheima.gan;
  2.  
  3. //信息类
  4. class Info{
  5. private String name="name"; //定义name属性,与下面set方法里的name属性分开
  6. private String content="content"; //定义content属性,与下mianset的content属性区分开
  7.  
  8. private boolean flag=true; //设置标识位,初始时生成
  9.  
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public String getContent() {
  17. return content;
  18. }
  19. public void setContent(String content) {
  20. this.content = content;
  21. }
  22.  
  23. //设置值
  24. public synchronized void set(String name,String content) {
  25. //如果标识位true,就不等待,标识为false,就等待
  26. while(!flag) {
  27. try {
  28. wait();
  29. } catch (InterruptedException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33.  
  34. this.setName(name); //设置名称
  35.  
  36. //休眠0.3s,再执行设置内容
  37. try {
  38. Thread.sleep(300);
  39. } catch (InterruptedException e) {
  40. e.printStackTrace();
  41. }
  42. this.setContent(content);
  43.  
  44. //设置标识为false,表示可以取走
  45. flag=false;
  46. super.notify();
  47. }
  48.  
  49. //取走值
  50. public synchronized void get() {
  51. //如果标识为true,表示现在时放入值的时候,消费者将等待
  52. while(flag) {
  53. try {
  54. super.wait();
  55. } catch (InterruptedException e) {
  56. e.printStackTrace();
  57. }
  58. }
  59.  
  60. //可以取值的时候先休眠0.3s
  61. try {
  62. Thread.sleep(300);
  63. } catch (InterruptedException e) {
  64. e.printStackTrace();
  65. }
  66.  
  67. //取值
  68. System.out.println(this.getName()+">=="+this.getContent());
  69. //去完值后设置标识位为true
  70. flag=true;
  71. //唤醒其他等待的线程
  72. super.notify();
  73. }
  74.  
  75. }
  76.  
  77. //生产者
  78. class Producer implements Runnable{
  79.  
  80. private Info info=null;
  81.  
  82. //构造方法
  83. public Producer(Info info) {
  84. this.info=info;
  85. }
  86.  
  87. @Override
  88. public void run() {
  89. //设置一个标识位为true
  90. boolean flag=true;
  91.  
  92. for(int i=0;i<10;i++) {
  93.  
  94. //如果标识位为true,添加内容1
  95. //如果标识位为false,添加内容2
  96. if(flag) {
  97. this.info.set("姓名1", "内容1");
  98. //将标识位改为false
  99. flag=false;
  100. }else {
  101. this.info.set("姓名2", "内容2");
  102. flag=true;
  103. }
  104. }
  105.  
  106. }
  107.  
  108. }
  109.  
  110. //消费者
  111. class Cusumer implements Runnable{
  112. private Info info=null;
  113. public Cusumer(Info info) {
  114. this.info=info;
  115. }
  116. @Override
  117. public void run() {
  118. for(int i=0;i<10;i++) {
  119. this.info.get();
  120. }
  121.  
  122. }
  123.  
  124. }
  125.  
  126. public class ProducerAndConsumerThread {
  127. public static void main(String[] args) {
  128. Info info=new Info();
  129.  
  130. Producer producer =new Producer(info);
  131. Cusumer cusumer=new Cusumer(info);
  132. //启动生成者
  133. new Thread(producer).start();
  134.  
  135. try {
  136. Thread.sleep(500);
  137. } catch (InterruptedException e) {
  138. e.printStackTrace();
  139. }
  140.  
  141. //启动消费者
  142. new Thread(cusumer).start();
  143. }
  144. }

  运行结果:

另外,在run方法中,二者循环的次数要相同,否则,当一方的循环结束时,另一方的循环依然继续,它会阻塞在wait()方法处,而等不到对方的notify通知。

————————————————
版权声明:本文为CSDN博主「兰亭风雨」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ns_code/article/details/17249321

Java线程——线程习题(二)生成者消费者的更多相关文章

  1. JAVA封装消息中间件调用二(kafka消费者篇)

    上一遍我简单介绍了kafka的生成者使用,调用方式比较简单,今天我给大家分享下封装kafka消费者,作为中间件,我们做的就是最大程度的解耦,使业务方接入我们依赖程度降到最低. 第一步,我们先配置一个消 ...

  2. JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止

    JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们 ...

  3. [Java并发编程(二)] 线程池 FixedThreadPool、CachedThreadPool、ForkJoinPool?为后台任务选择合适的 Java executors

    [Java并发编程(二)] 线程池 FixedThreadPool.CachedThreadPool.ForkJoinPool?为后台任务选择合适的 Java executors ... 摘要 Jav ...

  4. 【Java并发专题之二】Java线程基础

    使用线程更好的提高资源利用率,但也会带来上下文切换的消耗,频繁的内核态和用户态的切换消耗,如果代码设计不好,可能弊大于利. 一.线程 进程是分配资源的最小单位,线程是程序执行的最小单位:线程是依附于进 ...

  5. Java多线程总结(二)锁、线程池

    掌握Java中的多线程,必须掌握Java中的各种锁,以及了解Java中线程池的运用.关于Java多线程基础总结可以参考我的这篇博文Java多线程总结(一)多线程基础 转载请注明出处——http://w ...

  6. (删)Java线程同步实现二:Lock锁和Condition

    在上篇文章(3.Java多线程总结系列:Java的线程同步实现)中,我们介绍了用synchronized关键字实现线程同步.但在Java中还有一种方式可以实现线程同步,那就是Lock锁. 一.同步锁 ...

  7. “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. Java Thread系列(二)线程状态

    Java Thread系列(二)线程状态 一.线程的五种状态 新建状态(New):新创建了一个线程对象,尚未启动. 就绪状态(Runnable):也叫可运行状态.线程对象创建后,其他线程调用了该对象的 ...

  9. “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  10. java并发编程(二)----创建并运行java线程

    实现线程的两种方式 上一节我们了解了关于线程的一些基本知识,下面我们正式进入多线程的实现环节.实现线程常用的有两种方式,一种是继承Thread类,一种是实现Runnable接口.当然还有第三种方式,那 ...

随机推荐

  1. mybatis xml <if>判断字符串相等

    mybatis 映射文件中,if标签判断字符串相等,两种方式: 因为mybatis映射文件,是使用的ognl表达式,所以在判断字符串sex变量是否是字符串Y的时候, <if test=" ...

  2. 十五、SAP自定义结构体

    一.SAP的结构体是以BEGIN OF开始,以END OF结尾,代码如下: 二.输出结果如下

  3. list实体数据分组

    比如查询获取了60000条数据进行批量插入数据库,一次直接插入6万可能不是很好,可以将6万条数据按照5000分成几组,每组批量插入5000条 List<T> list = new List ...

  4. 新手学Java,有哪些入门知识点?

    很多小伙伴们在刚接触Java的时候,会有些迷茫,不知道该从哪里入手,不管是做前端还是后端,程序员都会用到JAVA,那该掌握哪些必要的基础知识呢.今天就跟大家分享新手学Java,有哪些入门知识点? 下面 ...

  5. NumPy 数组迭代

    章节 Numpy 介绍 Numpy 安装 NumPy ndarray NumPy 数据类型 NumPy 数组创建 NumPy 基于已有数据创建数组 NumPy 基于数值区间创建数组 NumPy 数组切 ...

  6. springboot - 映射HTTP Response Status Codes 到 静态 HTML页面

    1.总览 2.代码 1).pom.xml <dependencies> <dependency> <groupId>org.springframework.boot ...

  7. Spring入门之二-------SpringIoC之实例化Bean以及注入Bean

    一.实例化Bean 1. 通过默认构造方法实创建Bean public class Bean1 { public Bean1() { System.out.println(this.getClass( ...

  8. UVA - 1151 Buy or Build (买还是建)(并查集+二进制枚举子集)

    题意:平面上有n个点(1<=n<=1000),你的任务是让所有n个点连通.可以新建边,费用等于两端点欧几里德距离的平方.也可以购买套餐(套餐中的点全部连通).问最小费用. 分析: 1.先将 ...

  9. javascript 解决provisional headers are shown的过程

    请求没有被发送,因为是载入缓存资源. 大概是说 完全相同的请求间隔数毫秒(太短),导致加载失败,查看了chrome控制台发现 Provisional headers are shown 出现在 载入缓 ...

  10. AVCodec 结构体

    typedef struct AVCodec { // 标示Codec 的名字, 比如,"h264" "h263" 等. const char *name; / ...