zoukankan      html  css  js  c++  java
  • 生产者与消费者问题解决:解决先打印出消费的情况

    有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();//唤醒在此对象监视器上等待的单个线程,当前对象为syncstack
     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]);具体的打印时间就不确定了.   但是如果把输出打印放在同步代码块里面,就不会有这样的问题.因为会完成打印之后才会执行下一步.

  • 相关阅读:
    MYSQL profiling分析语句
    进程状态与僵尸进程、孤儿进程
    Nginx跨域设置
    Redis的应用场景
    Nginx的作用
    cgi、fast-cgi和php-fpm的介绍(作用)
    CoreDump开启和Swoole Tracker 3.0配置
    好题总结
    Atcoder总结 Part III
    Atcoder总结 Part II
  • 原文地址:https://www.cnblogs.com/imqsl/p/6086001.html
Copyright © 2011-2022 走看看