一个简答的生产者-消费者多线程模型

来源:互联网 发布:出售备案域名 编辑:程序博客网 时间:2024/04/29 21:53
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
packagetest;
 
importjava.util.Vector;
 
publicclass Producer extendsThread
{
    staticfinal int MAXQUEUE =5;
    privateVector messages =newVector();
  
    @Override
    publicvoid run()
    {
        try
        {
            while(true)
            {
                putMessage();//
                sleep(500);
            }
        }catch(InterruptedException e)
        {
        }
    }
  
    publicsynchronized void putMessage()throwsInterruptedException
    {
        while(messages.size()== MAXQUEUE)
        {
            System.out.println("messages full,wait......");
            wait();
        }
        String element = newjava.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
    publicsynchronized String getMessage() throwsInterruptedException
    {
       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());
        returnmessage;
      }
     
    publicstatic void main(String args[])
    {
        Producer producer =newProducer();
        producer.start();
        newConsumer (producer).start();
    }
  
}
classConsumer  extendsThread
{
    Producer producer;
    Consumer (Producer p)
    {
        producer = p;
    }
  
    @Override
    publicvoid 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 1714:24:19CST 2016;size:1
get message: Wed Feb 1714:24:19CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:19CST 2016;size:1
get message: Wed Feb 1714:24:19CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:20CST 2016;size:1
get message: Wed Feb 1714:24:20CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:20CST 2016;size:1
get message: Wed Feb 1714:24:20CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:21CST 2016;size:1
get message: Wed Feb 1714:24:21CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:21CST 2016;size:1
get message: Wed Feb 1714:24:21CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:22CST 2016;size:1
get message: Wed Feb 1714:24:22CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:22CST 2016;size:1
get message: Wed Feb 1714:24:22CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:23CST 2016;size:1
get message: Wed Feb 1714:24:23CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:23CST 2016;size:1
get message: Wed Feb 1714:24:23CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:24CST 2016;size:1
get message: Wed Feb 1714:24:24CST 2016;size:0
messages empty,wait......
put message: Wed Feb 1714:24:24CST 2016;size:1
get message: Wed Feb 1714:24:24CST 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
publicsynchronized String getMessage() throwsInterruptedException
   {
      String message = null;
      while(messages.size()==0)
       {
          System.out.println("messages empty,wait......");
          notify();
          returnnull;
       }
       //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());
       returnmessage;
     }
0 0