1
|
生产者消费者模型
|
1
|
同一段代码,分别设置produce和consumer的频率(通过sleep的长短控制)。
|
1
|
第一种情况produce后,sleep(
500
),consumer后,sleep(
100
),也就是取消息快,生产消息慢。这种情况正常。代码如下
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
package
test;
import
java.util.Vector;
public
class
Producer
extends
Thread
{
static
final
int
MAXQUEUE =
5
;
private
Vector messages =
new
Vector();
@Override
public
void
run()
{
try
{
while
(
true
)
{
putMessage();
//
sleep(
500
);
}
}
catch
(InterruptedException e)
{
}
}
public
synchronized
void
putMessage()
throws
InterruptedException
{
while
(messages.size()== MAXQUEUE)
{
System.out.println(
"messages full,wait......"
);
wait();
}
String element =
new
java.util.Date().toString();
messages.addElement(element);
System.out.println(
"put message: "
+element+
";size:"
+messages.size());
notify();
//Later, when the necessary event happens, the thread that is running it calls notify() from a block synchronized on the same object.
}
// Called by Consumer
public
synchronized
String getMessage()
throws
InterruptedException
{
String message =
null
;
while
(messages.size()==
0
)
{
System.out.println(
"messages empty,wait......"
);
wait();
}
//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.}
message =(String) messages.firstElement();
messages.removeElement(message);
System.out.println(
"get message: "
+message+
";size:"
+messages.size());
return
message;
}
public
static
void
main(String args[])
{
Producer producer =
new
Producer();
producer.start();
new
Consumer (producer).start();
}
}
class
Consumer
extends
Thread
{
Producer producer;
Consumer (Producer p)
{
producer = p;
}
@Override
public
void
run()
{
try
{
while
(
true
)
{
String message = producer.getMessage();
//System.out.println("get message: "+ message);
sleep(
100
);
}
}
catch
(InterruptedException e)
{
e.printStackTrace();
}
}
}
|
运行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
put message: Wed Feb
17
14
:
24
:
19
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
19
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
19
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
19
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
20
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
20
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
20
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
20
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
21
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
21
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
21
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
21
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
22
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
22
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
22
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
22
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
23
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
23
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
23
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
23
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
24
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
24
CST
2016
;size:
0
messages empty,wait......
put message: Wed Feb
17
14
:
24
:
24
CST
2016
;size:
1
get message: Wed Feb
17
14
:
24
:
24
CST
2016
;size:
0
messages empty,wait......
|
2、第二种情况,把两个sleep的时间调换下,也就是produce后,sleep(100),consumer后,sleep(500),也就是取消息慢,生产消息快。这种情况就出现了问题,如果队列满了,produce线程等待,consumer线程取完消息就hang住了,线程全部挂住了。运行结果如下:
put message: Wed Feb 17 14:27:00 CST 2016;size:1
get message: Wed Feb 17 14:27:00 CST 2016;size:0
put message: Wed Feb 17 14:27:00 CST 2016;size:1
put message: Wed Feb 17 14:27:00 CST 2016;size:2
put message: Wed Feb 17 14:27:00 CST 2016;size:3
put message: Wed Feb 17 14:27:00 CST 2016;size:4
get message: Wed Feb 17 14:27:00 CST 2016;size:3
put message: Wed Feb 17 14:27:01 CST 2016;size:4
put message: Wed Feb 17 14:27:01 CST 2016;size:5
messages full,wait......
get message: Wed Feb 17 14:27:00 CST 2016;size:4
get message: Wed Feb 17 14:27:00 CST 2016;size:3
get message: Wed Feb 17 14:27:00 CST 2016;size:2
get message: Wed Feb 17 14:27:01 CST 2016;size:1
get message: Wed Feb 17 14:27:01 CST 2016;size:0
messages empty,wait......
运行到这里就结束了,后面没有输出了
分析后,感觉应该和wait、notify有关系。
第二种情况下,生产消息快,队列慢了后就wait(),consumer线程取消息,直到队列空了之后,consumer线程只有一个wait(),并没有类似于notify的机制去通知produce线程,导致一直挂起;
而第一种情况下,取消息快,放消息慢,不存在队列满,队列只会空。队列空了后,consumer线程就wait(),等produce线程放入消息后,就会notify
还没想到解决办法,有哪个大神看出问题来就给个解答吧。
问题解决了,getMessage()函数改为如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
synchronized
String getMessage()
throws
InterruptedException
{
String message =
null
;
while
(messages.size()==
0
)
{
System.out.println(
"messages empty,wait......"
);
notify();
return
null
;
}
//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.}
message =(String) messages.firstElement();
messages.removeElement(message);
System.out.println(
"get message: "
+message+
";size:"
+messages.size());
return
message;
}
|