转载请注明出处:http://blog.csdn.net/ns_code/article/details/17249321

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

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

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

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

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

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

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

详细的实现代码如下:

  1. class Info{ // 定义信息类
  2. private String name = "name";//定义name属性,为了与下面set的name属性区别开
  3. private String content = "content" ;// 定义content属性,为了与下面set的content属性区别开
  4. private boolean flag = true ;   // 设置标志位,初始时先生产
  5. public synchronized void set(String name,String content){
  6. while(!flag){
  7. try{
  8. super.wait() ;
  9. }catch(InterruptedException e){
  10. e.printStackTrace() ;
  11. }
  12. }
  13. this.setName(name) ;    // 设置名称
  14. try{
  15. Thread.sleep(300) ;
  16. }catch(InterruptedException e){
  17. e.printStackTrace() ;
  18. }
  19. this.setContent(content) ;  // 设置内容
  20. flag  = false ; // 改变标志位,表示可以取走
  21. super.notify();
  22. }
  23. public synchronized void get(){
  24. while(flag){
  25. try{
  26. super.wait() ;
  27. }catch(InterruptedException e){
  28. e.printStackTrace() ;
  29. }
  30. }
  31. try{
  32. Thread.sleep(300) ;
  33. }catch(InterruptedException e){
  34. e.printStackTrace() ;
  35. }
  36. System.out.println(this.getName() +
  37. " --> " + this.getContent()) ;
  38. flag  = true ;  // 改变标志位,表示可以生产
  39. super.notify();
  40. }
  41. public void setName(String name){
  42. this.name = name ;
  43. }
  44. public void setContent(String content){
  45. this.content = content ;
  46. }
  47. public String getName(){
  48. return this.name ;
  49. }
  50. public String getContent(){
  51. return this.content ;
  52. }
  53. }
  54. class Producer implements Runnable{ // 通过Runnable实现多线程
  55. private Info info = null ;      // 保存Info引用
  56. public Producer(Info info){
  57. this.info = info ;
  58. }
  59. public void run(){
  60. boolean flag = true ;   // 定义标记位
  61. for(int i=0;i<10;i++){
  62. if(flag){
  63. this.info.set("姓名--1","内容--1") ;    // 设置名称
  64. flag = false ;
  65. }else{
  66. this.info.set("姓名--2","内容--2") ;    // 设置名称
  67. flag = true ;
  68. }
  69. }
  70. }
  71. }
  72. class Consumer implements Runnable{
  73. private Info info = null ;
  74. public Consumer(Info info){
  75. this.info = info ;
  76. }
  77. public void run(){
  78. for(int i=0;i<10;i++){
  79. this.info.get() ;
  80. }
  81. }
  82. }
  83. public class ThreadCaseDemo03{
  84. public static void main(String args[]){
  85. Info info = new Info(); // 实例化Info对象
  86. Producer pro = new Producer(info) ; // 生产者
  87. Consumer con = new Consumer(info) ; // 消费者
  88. new Thread(pro).start() ;
  89. //启动了生产者线程后,再启动消费者线程
  90. try{
  91. Thread.sleep(500) ;
  92. }catch(InterruptedException e){
  93. e.printStackTrace() ;
  94. }
  95. new Thread(con).start() ;
  96. }
  97. }

执行结果如下:

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

转: 【Java并发编程】之十三:生产者—消费者模型(含代码)的更多相关文章

  1. 【Java并发编程】:生产者—消费者模型

    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...

  2. 5 并发编程-(进程)-队列&生产者消费者模型

    1.队列的介绍 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的 创建队列的类(底层就是以管道和锁定的方式实现 ...

  3. Java并发编程(十三)线程间协作的两种方式:wait、notify、notifyAll和Condition

    在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果 ...

  4. 【Java并发编程】从CPU缓存模型到JMM来理解volatile关键字

    目录 并发编程三大特性 原子性 可见性 有序性 CPU缓存模型是什么 高速缓存为何出现? 缓存一致性问题 如何解决缓存不一致 JMM内存模型是什么 JMM的规定 Java对三大特性的保证 原子性 可见 ...

  5. java并发编程(十三)经典问题生产者消费者问题

    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据&q ...

  6. java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)

    这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...

  7. Java并发编程(十三)-- 线程池

    什么是线程池? 线程池就是以一个或多个线程循环执行多个应用逻辑的线程集合. 为什么用线程池? 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时 ...

  8. 【java并发编程】十三章:显式锁:LOCK

    java5以后,新增了显式锁,用于当内置锁不能满足需求后可选择的一种高级方案. lock接口的特点 与内置锁一样,他能提供互斥性,内存可见性,可重入等特征,与内置锁不同的是,Lock提供了一种无条件, ...

  9. Java并发编程(十三)同步容器类

    同步容器类 Vector.HashTable,我用的很少:Vecotr的实现和ArrayList挺接近的,不同的是Vector中很多的方法都用synchronized进行了同步.在不强调线程安全地时候 ...

  10. Java并发编程(十三)在现有的线程安全类中添加功能

    重用现有的类而不是创建新的类,可以降低工作量,开发风险以及维护成本. 有时候线程安全类可以支持我们所有的操作,但更多时候,现有的了类只能支持大部分的操作,此时就需要在不破坏线程安全性的情况下添加一个新 ...

随机推荐

  1. akoj-1319-四方定理

    四方定理 Time Limit:1000MS  Memory Limit:65536K Total Submit:28 Accepted:11 Description 数论中著名的"四方定理 ...

  2. PXE+kickstart无人值守安装CentOS 6

    本文目录: 1.1 PXE说明 1.2 PXE流程 1.3 部署环境说明 1.4 部署DHCP 1.5 部署TFTP 1.6 提供pxe的bootloader和相关配置文件 1.7 利用原版安装镜像获 ...

  3. 排座椅 2008 NOIP 普及组 第二题

    题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳.同学 ...

  4. ubuntu 15.10 安装jdk

    转http://www.bkjia.com/xtzh/881605.html 第一步,下载Linux版JDK 可以通过访问Oracle官网下载,或者直接通过命令行下载. lxh@ubuntu:~$ w ...

  5. ubuntu创建wifi热点(android可识别)亲测可用

    转自http://jingyan.baidu.com/article/ea24bc39b03fc6da62b331f0.html 如何在ubuntu系统下创建android可识别热点?一般环境下创建的 ...

  6. 社交系统/社群系统“ThinkSNS+”H5及PC端终于来了!一起来“找茬”

    [什么是TS+?] ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+,简称TS+. 还记得2017年 ...

  7. python编码问题一点通

    一.了解字符编码的知识储备 1. 文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就打开了启动了一个进程,是在内存中的,所以在编辑器编写的内容也都是存放与内存中的, ...

  8. 关于JS中涉及的常用类型转换及运算符表达式

    JS中的常用类型转换(一般用强制转换):1.强制转为整数:parseInt:写法:x = parseInt(x); 2.强制转换位小为:parseFloat:写法:x = parseFloat(x); ...

  9. css3文字与字体样式

    css3使用服务器端字体: <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  10. elastalert基于微信公众号报警

    环境部署 安装其它的必需包 yum install -y zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel   1,下载. ...