生产者与消费者问题解决:解决先打印出消费的情况

有bug 的代码(马士兵老师讲解的):

  1 <span style="font-size:14px;">/**生产者消费者问题,涉及到几个类
  2  * 第一,这个问题本身就是一个类,即主类
  3  * 第二,既然是生产者、消费者,那么生产者类和消费者类就是必须的
  4  * 第三,生产什么,消费什么,所以物品类是必须的,这里是馒头类
  5  * 第四,既然是线程,那么就不是一对一的,也就是说不是生产一个消费一个,既然这样,多生产的往哪里放,
  6  *      现实中就是筐了,在计算机中也就是数据结构,筐在数据结构中最形象的就是栈了,因此还要一个栈类
  7  */
  8 package thread;
  9
 10 public class ProduceConsume {
 11
 12     public static void main(String[] args) {
 13         SyncStack ss = new SyncStack();//建造一个装馒头的框
 14         Producer p = new Producer(ss);//新建一个生产者,使之持有框
 15         Consume c = new Consume(ss);//新建一个消费者,使之持有同一个框
 16         Thread tp = new Thread(p);//新建一个生产者线程
 17         Thread tc = new Thread(c);//新建一个消费者线程
 18         tp.start();//启动生产者线程
 19         tc.start();//启动消费者线程
 20     }
 21
 22 }
 23
 24 //馒头类
 25 class SteamBread{
 26     int id;//馒头编号
 27     SteamBread(int id){
 28         this.id = id;
 29     }
 30     public String toString(){
 31         return "steamBread:"+id;
 32     }
 33 }
 34
 35 //装馒头的框,栈结构
 36 class SyncStack{
 37     int index = 0;
 38     SteamBread[] stb = new SteamBread[6];//构造馒头数组,相当于馒头筐,容量是6
 39
 40     //放入框中,相当于入栈
 41     public synchronized void push(SteamBread sb){
 42         while(index==stb.length){//筐满了,即栈满,
 43             try {
 44                 this.wait();//让当前线程等待
 45             } catch (InterruptedException e) {
 46                 // TODO Auto-generated catch block
 47                 e.printStackTrace();
 48             }
 49         }
 50         this.notify();//唤醒在此对象监视器上等待的单个线程,即消费者线程
 51         stb[index] = sb;
 52         this.index++;
 53     }
 54
 55     //从框中拿出,相当于出栈
 56     public synchronized SteamBread pop(){
 57         while(index==0){//筐空了,即栈空
 58             try {
 59                 this.wait();
 60             } catch (InterruptedException e) {
 61                 // TODO Auto-generated catch block
 62                 e.printStackTrace();
 63             }
 64         }
 65         this.notify();
 66         this.index--;//push第n个之后,this.index++,使栈顶为n+1,故return之前要减一
 67         return stb[index];
 68     }
 69 }
 70
 71 //生产者类,实现了Runnable接口,以便于构造生产者线程
 72 class Producer implements Runnable{
 73     SyncStack ss = null;
 74     Producer(SyncStack ss){
 75         this.ss = ss;
 76     }
 77     @Override
 78     public void run() {
 79         // 开始生产馒头
 80         for(int i=0;i<20;i++){
 81             SteamBread stb = new SteamBread(i);
 82             ss.push(stb);
 83             System.out.println("生产了"+stb);
 84             try {
 85                 Thread.sleep(10);//每生产一个馒头,睡觉10毫秒
 86             } catch (InterruptedException e) {
 87                 // TODO Auto-generated catch block
 88                 e.printStackTrace();
 89             }
 90         }
 91     }
 92 }
 93
 94 //消费者类,实现了Runnable接口,以便于构造消费者线程
 95 class Consume implements Runnable{
 96     SyncStack ss = null;
 97     public Consume(SyncStack ss) {
 98         super();
 99         this.ss = ss;
100     }
101     @Override
102     public void run() {
103         // TODO Auto-generated method stub
104         for(int i=0;i<20;i++){//开始消费馒头
105             SteamBread stb = ss.pop();
106             System.out.println("消费了"+stb);
107             try {
108                 Thread.sleep(100);//每消费一个馒头,睡觉100毫秒。即生产多个,消费一个
109             } catch (InterruptedException e) {
110                 // TODO Auto-generated catch block
111                 e.printStackTrace();
112             }
113         }
114     }
115 }</span>  

解决方法:

http://blog.csdn.net/u013243986/article/details/48755183

看过 http://blog.csdn.net/thinkpadshi/article/details/8163751     下面的评论说:    感觉你的代码有问题啊,两个run()方法里面的打印语句的执行先后问题,假设开始在消费时index==0;这时wait()了,生产者便抢到锁,index+1;同时叫醒消费者,这个时候要是消费者先于生产者的打印了一条消费了0个,之后再打印生产了0个怎么办??!,我执行后也发现这样的问题,如果把100毫秒改为10毫秒,会有更多这样的情况产生.

于是自己改了下博主的代码:

  1 package deadLockThread;
  2
  3 public class SX {
  4     public static void main(String[] args) {
  5         ProductList pl = new ProductList();
  6         Factory f = new Factory(pl);
  7         Consumer c = new Consumer(pl);
  8
  9         Thread t1 = new Thread(f);
 10         Thread t2 = new Thread(c);
 11
 12         t1.start();
 13         t2.start();
 14
 15     }
 16 }
 17
 18 class Product {
 19     private int id;
 20
 21     Product(int id) {
 22         this.id = id;
 23     }
 24
 25     @Override
 26     public String toString() {
 27         return "Product [id=" + id + "]";
 28     }
 29
 30 }
 31
 32 class ProductList {
 33     int index = 0;
 34     private Product[] p = new Product[6];
 35
 36     public synchronized void push(Product pr) {
 37
 38         while (index == p.length) {
 39             try {
 40                 this.wait();
 41             } catch (InterruptedException e) {
 42                 // TODO Auto-generated catch block
 43                 e.printStackTrace();
 44             }
 45         }
 46         this.notify();
 47         p[index] = pr;
 48         <span style="color:#ff0000;">System.out.println("生产了" + p[index]);</span>
 49         index++;
 50
 51     }
 52
 53     public synchronized Product pop() {
 54
 55         while (index == 0) {
 56             try {
 57                 this.wait();
 58             } catch (InterruptedException e) {
 59                 // TODO Auto-generated catch block
 60                 e.printStackTrace();
 61             }
 62         }
 63         this.notify();
 64         index--;
 65         <span style="color:#ff0000;">System.out.println("消费了" + p[index]);</span>
 66         return p[index];
 67
 68     }
 69 }
 70
 71 class Factory implements Runnable {
 72
 73     private ProductList pl = null;
 74
 75     Factory(ProductList pl) {
 76         this.pl = pl;
 77     }
 78
 79     @Override
 80     public void run() {
 81         // TODO Auto-generated method stub
 82         for (int i = 0; i < 20; i++) {
 83             Product p = new Product(i);
 84             pl.push(p);
 85             try {
 86                 Thread.sleep(10);
 87             } catch (InterruptedException e) {
 88                 // TODO Auto-generated catch block
 89                 e.printStackTrace();
 90             }
 91         }
 92
 93     }
 94 }
 95
 96 class Consumer implements Runnable {
 97     private ProductList pl = null;
 98
 99     Consumer(ProductList pl) {
100         this.pl = pl;
101     }
102
103     @Override
104     public void run() {
105         // TODO Auto-generated method stub
106         for (int i = 0; i < 20; i++) {
107             Product p = pl.pop();
108             try {
109                 Thread.sleep(10);
110             } catch (InterruptedException e) {
111                 // TODO Auto-generated catch block
112                 e.printStackTrace();
113             }
114         }
115
116     }
117 }

我就只是改动了  输出的位置 这是由于System.out.println()函数不是立刻就打印的,它要调用其他的函数来完成输出,所以System.out.println("生产了" + p[index]);  还有 System.out.println("消费了" + p[index]);具体的打印时间就不确定了.   但是如果把输出打印放在同步代码块里面,就不会有这样的问题.因为会完成打印之后才会执行下一步.

时间: 2024-10-12 03:31:27

生产者与消费者问题解决:解决先打印出消费的情况的相关文章

JAVA学习第二十六课(多线程(六))- 多生产者多消费者问题

多生产者多消费者问题 以生产馒头 消费馒头为例. class Resource { private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name) { if (flag) { try { this.wait(); } catch (Exception e) { // TODO: handle exception } } this.

多线程——生产者与消费者(多)问题解决

package 多线程; public class PandC { public static void main(String[] args) { // Producer p= new Producer(); // Consumer c = new Consumer(); // new Thread(p,"生产者").start(); // new Thread(p,"生产者").start(); // new Thread(c,"消费者").

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力. 什么是生产者消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待

同步函数 生产者和消费者模式 加强版(多人生产和多人消费)

曾经搞了半天, 生产者和消费者模式  加强版(多人生产 多人消费 ).. 以前的代码格式就不再吐槽了(以后努力改进) //输出结果是一个无限循环 import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 多个生产者&多个消费者模式 * 多个生产者不断生产,多个消费者不停的消费

JAVA-初步认识-第十四章-线程间通信-多生产者多消费者问题-JDK1.5解决办法

一. 在1.5版本中,将原先的形式进行了改变,但是功能并没有任何变化,那么这么做的原因是什么? 以前,我们一个锁上只有一组监视器,这组监视器既监视着生产者,又监视着消费者.这组监视器能将生产者和消费者全都wait,也能将生产者和消费者全都唤醒.或者notify也行,它也能将其中一条线程唤醒,而其中一条不能确定是谁,有可能是本方,也可能是对方. 现在我们的线程进行了分类,一组负责生产,一组负责消费.我们希望生产者能够唤醒消费者,消费者唤醒生产者.如果搞两个监视器,一组监视生产者,一组监视消费者,这

对生产者和消费者问题的另一个解决办法是使用QWaitCondition(封装好了wakeOne,wakeAll,而且与QReadWriteLock对接,几乎是万能的办法)

对生产者和消费者问题的另一个解决办法是使用QWaitCondition,它允许线程在一定条件下唤醒其他线程.其中wakeOne()函数在条件满足时随机唤醒一个等待线程,而wakeAll()函数则在条件满足时唤醒所有等待线程. 1.bool wait(QMutex * mutex,unsigned long time = ULONG_MAX) 1) 释放锁定的mutex 2) 在线程对象上等待 mutex必须由调用线程进行初锁定 .注意调用wait的话,会自动调用unlock解锁之前锁住的资源,不

rabbitmq 生产者 消费者(多个线程消费同一个队列里面的任务。)

rabbitmq作为消息队列可以有消息消费确认机制,redis的list结构可以简单充当消息队列,但不具备消费确认机制,随意关停程序,会丢失一部分正在程序中处理但还没执行完的消息. 使用rabbitmq的最常用库pika # coding=utf-8 """ 一个通用的rabbitmq生产者和消费者.使用多个线程消费同一个消息队列. """ import abc import functools import time from threadin

多线程操作实例——生产者与消费者

面对多线程学习生产者与消费者是最基本的实例 对于java后端开发的人员必须要掌握,还有考研考试计算机操作系统的同鞋. 下面是三个实例对于生产者与消费者的的例子,层层递进,逐步解决问题. 问题:生产者——设置信息名字name,和内容content 消费者——负责取出设置的信息. 一.基本实现 由于线程的不确定性可能出现以下问题: (1)消费者取出的信息不匹配,即不是由同一个生产者设置的信息 (2)生产者生产了多个信息,消费者才开始取出信息,或消费者取出的重复的信息. 上面的问题下面会逐一解决,下面

生产者与消费者问题

***********************************************声明****************************************************** 原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不足,欢迎斧正! *******************************************