今天试着用java写了下生产者消费者模式,还发现了一些有趣的问题,这里记录一下。
首先说一下大概思想,其实是参照了csdn上别的同学的代码,建立一个仓库类,其中保存着一个队列(linkedList实现)和向队列中添加货物和移去货物的操作,这些操作中对队列加锁以处理并发问题,再建立数个生产者线程和消费者线程来调用这些操作。
以下是代码(请无视各种奇怪的拼写。。):
仓库类
<pre name="code" class="java">class storage{
LinkedList<Integer> list=new LinkedList<Integer>();
int max=50;
int min=20;
void add(){
synchronized (list) {
//注意这里采用if判定
if(list.size()>=max){
System.out.println("storage too much");
try{
list.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
//step
}
//必须再判定一次,因为if 只判定一次,在后面使用notifyAll()之后,程序从step
//处开始,不经判定可导致生产量超出上限
if(list.size()<max)list.add(1);
System.out.println("already has"+list.size());
list.notifyAll();
}
}
void consum(){
synchronized (list) {
//采用while
while(list.size()<=min){
System.out.println("storage not enough");
try{
list.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
list.remove();
System.out.println("cosum already has"+list.size());
list.notifyAll();
}
}
}
生产者线程:
<pre name="code" class="java"> class producer extends Thread{
storage s;
public producer(storage s) {
// TODO Auto-generated constructor stub
this.s=s;
}
@Override
public void run() {
// TODO Auto-generated method stub
produce();
}
void produce(){
while (true)
s.add();
}
}
消费者线程
class cosumer extends Thread{
storage s;
public cosumer(storage s) {
// TODO Auto-generated constructor stub
this.s=s;
}
@Override
public void run() {
// TODO Auto-generated method stub
consum();
}
void consum(){
while(true)
s.consum();
}
}
main函数测试:
public static void main(String[] args) {
storage s=new storage();
for(int i=1;i<3;i++){
producer p=new producer(s);
p.start();
}
for(int i=1;i<8;i++){
cosumer c=new cosumer(s);
c.start();
}
}
运行后货物不停地被生存和消费,但总数不会大于max,不会小于min。
好玩之处在仓库类中,add()方法每次开始都要测试仓库存量是否大于max,如果大于则当前线程被阻塞。这里用的是if语句,而整个if语句一结束要再次测试一下库存才能进入下一步操作。原因是add()方法使用了notifyAll()方法来唤醒所有线程,而线程被唤醒后是从代码注释//step处开始执行,这个时候如果没有再测试一下的话,在仓库已满的情况下,仍会执行后面的代码,导致仓库中的存量大于max。而在consum方法中采用while语句来判定,线程回复后仍要在while模块内进行判断,就不会有这种异常出现啦!