1
+ /**
2
+ *
3
+ */
4
+ package sporadic .producer_consumer_example ;
5
+
6
+ import java .util .LinkedList ;
7
+ import java .util .Queue ;
8
+ import java .util .Random ;
9
+
10
+ /**
11
+ * 在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。
12
+ * 举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,
13
+ * 因为队列缓冲区中有内容待消费(不为空)。相应的,消费者可以通知生产者可以开始生成更多的数据,
14
+ * 因为当它消耗掉某些数据后缓冲区不再为满。
15
+ *
16
+ * 如何使用Wait
17
+ * 尽管关于wait和notify的概念很基础,它们也都是Object类的函数,但用它们来写代码却并不简单。
18
+ * 如果你在面试中让应聘者来手写代码,用wait和notify解决生产者消费者问题,我几乎可以肯定他们中的大多数都会无所适从或者犯下一些错误,
19
+ * 例如在错误的地方使用 synchronized 关键词,没有对正确的对象使用wait,或者没有遵循规范的代码方法。
20
+ * 说实话,这个问题对于不常使用它们的程序员来说确实令人感觉比较头疼。
21
+ *
22
+ * 第一个问题就是,我们怎么在代码里使用wait()呢?
23
+ * 因为wait()并不是Thread类下的函数,我们并不能使用Thread.call()。
24
+ * 事实上很多Java程序员都喜欢这么写,因为它们习惯了使用Thread.sleep(),所以他们会试图使用wait() 来达成相同的目的,但很快他们就会发现这并不能顺利解决问题。
25
+ *
26
+ * 正确的方法是对在多线程间共享的那个Object来使用wait。
27
+ *
28
+ * 在生产者消费者问题中,这个共享的Object就是那个缓冲区队列。
29
+ *
30
+ * 第二个问题是,既然我们应该在synchronized的函数或是对象里调用wait,那哪个对象应该被synchronized呢?
31
+ * 答案是,那个你希望上锁的对象就应该被synchronized,即那个在多个线程间被共享的对象。在生产者消费者问题中,应该被synchronized的就是那个缓冲区队列。*/
32
+
33
+ /**
34
+ * Simple Java program to demonstrate How to use wait, notify and notifyAll()
35
+ * method in Java by solving producer consumer problem.
36
+ *
37
+ * @author Javin Paul
38
+ */
39
+ public class ProducerConsumerInJava {
40
+ public static void main (String args []) {
41
+ System .out .println ("How to use wait and notify method in Java" );
42
+ System .out .println ("Solving Producer Consumper Problem" );
43
+ Queue <Integer > sharedQueueOrBuffer = new LinkedList <>();
44
+ int maxSize = 10 ;
45
+ Thread producer = new Producer (sharedQueueOrBuffer , maxSize , "PRODUCER" );
46
+ Thread consumer = new Consumer (sharedQueueOrBuffer , maxSize , "CONSUMER" );
47
+ producer .start ();
48
+ consumer .start ();
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Producer Thread will keep producing values for Consumer to consumer. It will
54
+ * use wait() method when Queue is full and use notify() method to send
55
+ * notification to Consumer Thread.
56
+ *
57
+ */
58
+ class Producer extends Thread {
59
+ private Queue <Integer > queue ;
60
+ private int maxSize ;
61
+
62
+ public Producer (Queue <Integer > queue , int maxSize , String name ) {
63
+ super (name );
64
+ this .queue = queue ;
65
+ this .maxSize = maxSize ;
66
+ }
67
+
68
+ @ Override
69
+ public void run () {
70
+ while (true ) {
71
+ synchronized (queue ) {
72
+ while (queue .size () == maxSize ) {
73
+ try {
74
+ System .out .println ("Queue is full, "
75
+ + "Producer thread waiting for "
76
+ + "consumer to take something from queue" );
77
+ queue .wait ();
78
+ } catch (Exception ex ) {
79
+ ex .printStackTrace ();
80
+ }
81
+ }
82
+ Random random = new Random ();
83
+ int i = random .nextInt ();
84
+ System .out .println ("Producing value : " + i );
85
+ queue .add (i );
86
+ queue .notifyAll ();
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Consumer Thread will consume values form shared queue. It will also use
94
+ * wait() method to wait if queue is empty. It will also use notify method to
95
+ * send notification to producer thread after consuming values from queue.
96
+ *
97
+ */
98
+ class Consumer extends Thread {
99
+ private Queue <Integer > queue ;
100
+ private int maxSize ;
101
+
102
+ public Consumer (Queue <Integer > queue , int maxSize , String name ) {
103
+ super (name );
104
+ this .queue = queue ;
105
+ this .maxSize = maxSize ;
106
+ }
107
+
108
+ @ Override
109
+ public void run () {
110
+ while (true ) {
111
+ synchronized (queue ) {
112
+ while (queue .isEmpty ()) {
113
+ System .out .println ("Queue is empty,"
114
+ + "Consumer thread is waiting"
115
+ + " for producer thread to put something in queue" );
116
+ try {
117
+ queue .wait ();
118
+ } catch (Exception ex ) {
119
+ ex .printStackTrace ();
120
+ }
121
+ }
122
+ System .out .println ("Consuming value : " + queue .remove ());
123
+ queue .notifyAll ();
124
+ }
125
+ }
126
+ }
127
+ }
0 commit comments