1 /*@author shijin
2 * 生产者与消费者模型中,要保证以下几点:
3 * 1 同一时间内只能有一个生产者生产 生产方法加锁sychronized
4 * 2 同一时间内只能有一个消费者消费 消费方法加锁sychronized
5 * 3 生产者生产的同时消费者不能消费 生产方法加锁sychronized
6 * 4 消费者消费的同时生产者不能生产 消费方法加锁sychronized
7 * 5 共享空间空时消费者不能继续消费 消费前循环判断是否为空,空的话将该线程wait,释放锁允许其他同步方法执行
8 * 6 共享空间满时生产者不能继续生产 生产前循环判断是否为满,满的话将该线程wait,释放锁允许其他同步方法执行
9 */
10
11 //主类
12 class ProducerConsumer
13 {
14 public static void main(String[] args)
15 {
16 StackBasket s = new StackBasket();
17 Producer p = new Producer(s);
18 Consumer c = new Consumer(s);
19 Thread tp = new Thread(p);
20 Thread tc = new Thread(c);
21 tp.start();
22 tc.start();
23 }
24 }
25
26 //
27 class Mantou
28 {
29 private int id;
30
31 Mantou(int id){
32 this.id = id;
33 }
34
35 public String toString(){
36 return "Mantou :" + id;
37 }
38 }
39
40 //共享栈空间
41 class StackBasket
42 {
43 Mantou sm[] = new Mantou[6];
44 int index = 0;
45
46 /**
47 * show 生产方法.
48 * show 该方法为同步方法,持有方法锁;
49 * show 首先循环判断满否,满的话使该线程等待,释放同步方法锁,允许消费;
50 * show 当不满时首先唤醒正在等待的消费方法,但是也只能让其进入就绪状态,
51 * show 等生产结束释放同步方法锁后消费才能持有该锁进行消费
52 * @param m 元素
53 * @return 没有返回值
54 */
55
56 public synchronized void push(Mantou m){
57 try{
58 while(index == sm.length){
59 System.out.println("!!!!!!!!!生产满了!!!!!!!!!");
60 this.wait();
61 }
62 this.notify();
63 }catch(InterruptedException e){
64 e.printStackTrace();
65 }catch(IllegalMonitorStateException e){
66 e.printStackTrace();
67 }
68
69 sm[index] = m;
70 index++;
71 System.out.println("生产了:" + m + " 共" + index + "个馒头");
72 }
73
74 /**
75 * show 消费方法
76 * show 该方法为同步方法,持有方法锁
77 * show 首先循环判断空否,空的话使该线程等待,释放同步方法锁,允许生产;
78 * show 当不空时首先唤醒正在等待的生产方法,但是也只能让其进入就绪状态
79 * show 等消费结束释放同步方法锁后生产才能持有该锁进行生产
80 * @param b true 表示显示,false 表示隐藏
81 * @return 没有返回值
82 */
83 public synchronized Mantou pop(){
84 try{
85 while(index == 0){
86 System.out.println("!!!!!!!!!消费光了!!!!!!!!!");
87 this.wait();
88 }
89 this.notify();
90 }catch(InterruptedException e){
91 e.printStackTrace();
92 }catch(IllegalMonitorStateException e){
93 e.printStackTrace();
94 }
95 index--;
96 System.out.println("消费了:---------" + sm[index] + " 共" + index + "个馒头");
97 return sm[index];
98 }
99 }
100
101 class Producer implements Runnable
102 {
103 StackBasket ss = new StackBasket();
104 Producer(StackBasket ss){
105 this.ss = ss;
106 }
107
108 /**
109 * show 生产进程.
110 */
111 public void run(){
112 for(int i = 0;i < 20;i++){
113 Mantou m = new Mantou(i);
114 ss.push(m);
115 // System.out.println("生产了:" + m + " 共" + ss.index + "个馒头");
116 // 在上面一行进行测试是不妥的,对index的访问应该在原子操作里,因为可能在push之后此输出之前又消费了,会产生输出混乱
117 try{
118 Thread.sleep((int)(Math.random()*500));
119 }catch(InterruptedException e){
120 e.printStackTrace();
121 }
122 }
123 }
124 }
125
126 class Consumer implements Runnable
127 {
128 StackBasket ss = new StackBasket();
129 Consumer(StackBasket ss){
130 this.ss = ss;
131 }
132
133 /**
134 * show 消费进程.
135 */
136 public void run(){
137 for(int i = 0;i < 20;i++){
138 Mantou m = ss.pop();
139 // System.out.println("消费了:---------" + m + " 共" + ss.index + "个馒头");
140 // 同上 在上面一行进行测试也是不妥的,对index的访问应该在原子操作里,因为可能在pop之后此输出之前又生产了,会产生输出混乱
141 try{
142 Thread.sleep((int)(Math.random()*1000));
143 }catch(InterruptedException e){
144 e.printStackTrace();
145 }
146 }
147 }
148 }