您的位置:首页 > 其它

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

2016-11-21 16:46 447 查看
有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]);具体的打印时间就不确定了. 但是如果把输出打印放在同步代码块里面,就不会有这样的问题.因为会完成打印之后才会执行下一步.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐