本来打算在线程最后的章节来实现生产者消费者模式的,这里就先实现个简单的试试水;好让童鞋们更顺水的了解这三个方法的使用。
例子1
1.package thread;
2.
3./**
4. * main主函数
5. *
6. * @author ciding
7. * @createTime Dec 12, 2011 3:05:44 PM
8. *
9. */
10.public class ConsumerAndProducerThread {
11. public static void main(String[] args) {
12. Storage storage = new Storage(40,100);
13.
14. /**
15. * 一共消费了60+61+62+63+64=310
16. */
17. for(int i=0; i<5; i++){
18. Consumer c = new Consumer(60+i, storage);
19. c.start();
20. }
21.
22. /**
23. * 一共生产了10+20+30+40+15+25+35+45+49+51=320 再加上初始化的40 一共360
24. */
25. Producer p1 = new Producer(10,storage); //生产10
26. Producer p2 = new Producer(20,storage); //生产20
27. Producer p3 = new Producer(30,storage); //生产30
28. Producer p4 = new Producer(40,storage); //生产40
29. Producer p5 = new Producer(15,storage); //生产15
30. Producer p6 = new Producer(25,storage); //生产25
31. Producer p7 = new Producer(35,storage); //生产35
32. Producer p8 = new Producer(45,storage); //生产45
33. Producer p9 = new Producer(49,storage); //生产49
34. Producer p10 = new Producer(51,storage); //生产51
35.
36. p1.start();
37. p2.start();
38. p3.start();
39. p4.start();
40. p5.start();
41. p6.start();
42. p7.start();
43. p8.start();
44. p9.start();
45. p10.start();
46. }
47.}
48.
49./**
50. * 生产者
51. *
52. * @author ciding
53. * @createTime Dec 12, 2011 3:05:35 PM
54. *
55. */
56.class Consumer extends Thread {
57. private int neednum; // 生产产品的数量
58. private Storage storage; // 仓库
59.
60. Consumer(int neednum, Storage storage) {
61. this.neednum = neednum;
62. this.storage = storage;
63. }
64.
65. public void run() {
66. storage.consume(neednum);// 消费指定数量的产品
67. }
68.}
69.
70./**
71. * 消费者
72. *
73. * @author ciding
74. * @createTime Dec 12, 2011 3:06:03 PM
75. *
76. */
77.class Producer extends Thread {
78. private int neednum; // 生产产品的数量
79. private Storage storage; // 仓库
80.
81. Producer(int neednum, Storage storage) {
82. this.neednum = neednum;
83. this.storage = storage;
84. }
85.
86. public void run() {
87. storage.produce(neednum); // 生产指定数量的产品
88. }
89.}
90.
91./**
92. * 仓库
93. *
94. * @author ciding
95. * @createTime Dec 12, 2011 3:06:31 PM
96. *
97. */
98.class Storage {
99. public int max_size = 100; // 库存量初始值
100. public int curnum = 0; // 当前库存量初始值
101.
102. Storage() {
103. }
104.
105. Storage(int curnum, int max_size) {
106. this.curnum = curnum;
107. this.max_size = max_size;
108. }
109.
110. /**
111. * 生产指定数量的产品
112. *
113. * @param neednum
114. */
115. public synchronized void produce(int neednum) {
116. /* 测试是否需要生产 */
117. while (neednum + curnum > max_size) {
118. try {
119. Thread.sleep(100); //模拟运行时间
120.
121. System.out.println("要生产的产品数量" + neednum + "超过剩余库存量"
122. + (max_size - curnum) + ",暂时不能执行生产任务!");
123. wait(); // 当前的生产线程等待
124. } catch (InterruptedException e) {
125. e.printStackTrace();
126. }
127. }
128.
129. curnum += neednum; // 满足生产条件,则进行生产,这里简单的更改当前库存量
130. System.out.println("已经生产了" + neednum + "个产品,现仓储量为" + curnum);
131.
132. notify(); // 唤醒在此对象监视器上等待的某个线程
133. }
134.
135. /**
136. * 消费指定数量的产品
137. *
138. * @param neednum
139. */
140. public synchronized void consume(int neednum) {
141. // 测试是否可消费
142. while (curnum < neednum) {
143. try {
144. Thread.sleep(100);//模拟运行时间
145.
146. System.out.println("仓储量为:" + curnum + ",不够消费:" + neednum);
147. wait();// 当前的生产线程等待
148. } catch (InterruptedException e) {
149. e.printStackTrace();
150. }
151. }
152. curnum -= neednum; // 满足消费条件,则进行消费,这里简单的更改当前库存量
153. System.out.println("已经消费了" + neednum + "个产品,现仓储量为" + curnum);
154.
155. notify(); // 唤醒在此对象监视器上等待的某个线程
156. }
157.}
2.
3./**
4. * main主函数
5. *
6. * @author ciding
7. * @createTime Dec 12, 2011 3:05:44 PM
8. *
9. */
10.public class ConsumerAndProducerThread {
11. public static void main(String[] args) {
12. Storage storage = new Storage(40,100);
13.
14. /**
15. * 一共消费了60+61+62+63+64=310
16. */
17. for(int i=0; i<5; i++){
18. Consumer c = new Consumer(60+i, storage);
19. c.start();
20. }
21.
22. /**
23. * 一共生产了10+20+30+40+15+25+35+45+49+51=320 再加上初始化的40 一共360
24. */
25. Producer p1 = new Producer(10,storage); //生产10
26. Producer p2 = new Producer(20,storage); //生产20
27. Producer p3 = new Producer(30,storage); //生产30
28. Producer p4 = new Producer(40,storage); //生产40
29. Producer p5 = new Producer(15,storage); //生产15
30. Producer p6 = new Producer(25,storage); //生产25
31. Producer p7 = new Producer(35,storage); //生产35
32. Producer p8 = new Producer(45,storage); //生产45
33. Producer p9 = new Producer(49,storage); //生产49
34. Producer p10 = new Producer(51,storage); //生产51
35.
36. p1.start();
37. p2.start();
38. p3.start();
39. p4.start();
40. p5.start();
41. p6.start();
42. p7.start();
43. p8.start();
44. p9.start();
45. p10.start();
46. }
47.}
48.
49./**
50. * 生产者
51. *
52. * @author ciding
53. * @createTime Dec 12, 2011 3:05:35 PM
54. *
55. */
56.class Consumer extends Thread {
57. private int neednum; // 生产产品的数量
58. private Storage storage; // 仓库
59.
60. Consumer(int neednum, Storage storage) {
61. this.neednum = neednum;
62. this.storage = storage;
63. }
64.
65. public void run() {
66. storage.consume(neednum);// 消费指定数量的产品
67. }
68.}
69.
70./**
71. * 消费者
72. *
73. * @author ciding
74. * @createTime Dec 12, 2011 3:06:03 PM
75. *
76. */
77.class Producer extends Thread {
78. private int neednum; // 生产产品的数量
79. private Storage storage; // 仓库
80.
81. Producer(int neednum, Storage storage) {
82. this.neednum = neednum;
83. this.storage = storage;
84. }
85.
86. public void run() {
87. storage.produce(neednum); // 生产指定数量的产品
88. }
89.}
90.
91./**
92. * 仓库
93. *
94. * @author ciding
95. * @createTime Dec 12, 2011 3:06:31 PM
96. *
97. */
98.class Storage {
99. public int max_size = 100; // 库存量初始值
100. public int curnum = 0; // 当前库存量初始值
101.
102. Storage() {
103. }
104.
105. Storage(int curnum, int max_size) {
106. this.curnum = curnum;
107. this.max_size = max_size;
108. }
109.
110. /**
111. * 生产指定数量的产品
112. *
113. * @param neednum
114. */
115. public synchronized void produce(int neednum) {
116. /* 测试是否需要生产 */
117. while (neednum + curnum > max_size) {
118. try {
119. Thread.sleep(100); //模拟运行时间
120.
121. System.out.println("要生产的产品数量" + neednum + "超过剩余库存量"
122. + (max_size - curnum) + ",暂时不能执行生产任务!");
123. wait(); // 当前的生产线程等待
124. } catch (InterruptedException e) {
125. e.printStackTrace();
126. }
127. }
128.
129. curnum += neednum; // 满足生产条件,则进行生产,这里简单的更改当前库存量
130. System.out.println("已经生产了" + neednum + "个产品,现仓储量为" + curnum);
131.
132. notify(); // 唤醒在此对象监视器上等待的某个线程
133. }
134.
135. /**
136. * 消费指定数量的产品
137. *
138. * @param neednum
139. */
140. public synchronized void consume(int neednum) {
141. // 测试是否可消费
142. while (curnum < neednum) {
143. try {
144. Thread.sleep(100);//模拟运行时间
145.
146. System.out.println("仓储量为:" + curnum + ",不够消费:" + neednum);
147. wait();// 当前的生产线程等待
148. } catch (InterruptedException e) {
149. e.printStackTrace();
150. }
151. }
152. curnum -= neednum; // 满足消费条件,则进行消费,这里简单的更改当前库存量
153. System.out.println("已经消费了" + neednum + "个产品,现仓储量为" + curnum);
154.
155. notify(); // 唤醒在此对象监视器上等待的某个线程
156. }
157.}
运行结果:
仓储量为:40,不够消费:60
已经生产了51个产品,现仓储量为91
要生产的产品数量49超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量45超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量35超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量25超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量15超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量40超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量30超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量20超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量10超过剩余库存量9,暂时不能执行生产任务!
已经消费了64个产品,现仓储量为27
仓储量为:27,不够消费:63
仓储量为:27,不够消费:62
仓储量为:27,不够消费:61
已经生产了49个产品,现仓储量为76
已经消费了60个产品,现仓储量为16
已经生产了35个产品,现仓储量为51
已经生产了25个产品,现仓储量为76
已经生产了15个产品,现仓储量为91
要生产的产品数量40超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量45超过剩余库存量9,暂时不能执行生产任务!
已经生产了51个产品,现仓储量为91
要生产的产品数量49超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量45超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量35超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量25超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量15超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量40超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量30超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量20超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量10超过剩余库存量9,暂时不能执行生产任务!
已经消费了64个产品,现仓储量为27
仓储量为:27,不够消费:63
仓储量为:27,不够消费:62
仓储量为:27,不够消费:61
已经生产了49个产品,现仓储量为76
已经消费了60个产品,现仓储量为16
已经生产了35个产品,现仓储量为51
已经生产了25个产品,现仓储量为76
已经生产了15个产品,现仓储量为91
要生产的产品数量40超过剩余库存量9,暂时不能执行生产任务!
要生产的产品数量45超过剩余库存量9,暂时不能执行生产任务!
线程没有关闭,一直还在wait。
细心的童鞋,应该已经看出问题的所在,在调用wait后,程序是通过调用notify()方法来唤醒在此对象监视器上等待的某个线程。
另外,根据输出的结果,我们来分析一个wait()与notify()的调用。
a为能运行的生产者 a=10
b为能运行的消费者 b=5
0:调用消费者,不成功,等待。(a=10,b=4)
1:调用了生产者,成功,唤醒了一个生产者/消费者。(a=1,b=5)
2:调用了10个生产,其中9个等待。(a=0,b=5)
3:调用一个消费,成功,然后调用notify()唤醒一个生产。(a=1,b=4)
4:连着调用三个消费,不成功,等待。(a=1,b=1)
5:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=1,b=1)或略
6:调用消费者,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
7:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
8:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
9:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
10:调用唤醒的那个生产者,不成功,等待。(a=1,b=0)或略
11:调用唤醒的那个生产者,不成功,等待。(a=0,b=0)或略
1:调用了生产者,成功,唤醒了一个生产者/消费者。(a=1,b=5)
2:调用了10个生产,其中9个等待。(a=0,b=5)
3:调用一个消费,成功,然后调用notify()唤醒一个生产。(a=1,b=4)
4:连着调用三个消费,不成功,等待。(a=1,b=1)
5:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=1,b=1)或略
6:调用消费者,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
7:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
8:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
9:调用唤醒的那个生产者,生产,成功,唤醒了一个生产者/消费者。(a=2,b=0)或略
10:调用唤醒的那个生产者,不成功,等待。(a=1,b=0)或略
11:调用唤醒的那个生产者,不成功,等待。(a=0,b=0)或略
到此,可运行的线程为0,都在等待状态。
因为两个程序等待的对象都是curnum(产品量),所以唤醒的线程可能是生产者也可能是消费者。
如果将程序中的notify()方法换成notifyAll()方法,及可实现简单的生产者消费者。
那是不是两个notify()方法都要换呢?
这一点,就留给童鞋们自己思考了,如果你已经把上面的内容仔细阅读,相信你会懂的其中的原理。
关于同步的话题,对于synchronized的解讲,就先告一段落了。接下来的章节将从JDK 1.5及以上版本提供的Lock进行解读。