黑马程序员--生产者和消费者模式

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

在学习了毕老师的生产者消费者模式,下面写下关于生产者消费者模式的理解,生产者生产产品到资源类中,而消费者冲资源类中取出产品并消费,如果只开启一个生产者的线程,一个消费者的线程,不会出问题如果开启两个生产者,两个消费者就会出现问题代码如下面所示:







class ProducerConsumerDemo 
{
public static void main(String[] args) 
{
Resource r = new Resource();


Producer pro = new Producer(r);
Consumer con = new Consumer(r);


Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);


t1.start();
t2.start();
t3.start();
t4.start();


}
}







class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
//  t1    t2
public synchronized void set(String name)
{
if(flag)
try{this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)
this.name = name+"--"+count++;


System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
this.notify();
}




//  t3   t4  
public synchronized void out()
{
if(!flag)
try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
this.notify();
}
}


class Producer implements Runnable
{
private Resource res;


Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set("+商品+");
}
}
}


class Consumer implements Runnable
{
private Resource res;


Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}



代码如上所示,这样如果启用四个线程,如果线程t1进来发现 flag为false,那么他就进行生产,而生产完后,将flag设置成true;通知t2, t2线程进来后发现flag为true,就进入挂起状态,t3进入后,发现flag为true 就进行消费,然后将flag变成false ,这样t4线程进来就会挂起,这样四个线程就全部挂起,程序停止,要解决这个问题就要将notify()改为notifyAll(),notifyAll()是通知全部线程,notify()只通知程序内线程,改为notifyAll()还是会出问题。假如改成notifyAll() t1,进入发现flag为false 进进行生产,生产完,把flag变成了true,通知其他线程,假如t2进入 ,发现flag为true ,就会挂起,这时候t3进入,发现flag为true,就进行消费产品,然后将flag变成flag,这时候通知别的线程访问,这时候t2如果被唤起,则不会重新进行判断,就进行生产,造成t1制作的产品没法被消费,解决这个问题的方法是将if(flag)变成while(flag)这样,while循环在每次执行的 时候都会进行判断,就会消除了这种情况。

改正后的代码如下







class ProducerConsumerDemo 
{
public static void main(String[] args) 
{
Resource r = new Resource();


Producer pro = new Producer(r);
Consumer con = new Consumer(r);


Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);


t1.start();
t2.start();
t3.start();
t4.start();


}
}


/*
对于多个生产者和消费者。
为什么要定义while判断标记。
原因:让被唤醒的线程再一次判断标记。




为什么定义notifyAll,
因为需要唤醒对方线程。
因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。


*/




class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
//  t1    t2
public synchronized void set(String name)
{
while(flag)
try{this.wait();}catch(Exception e){}//t1(放弃资格)  t2(获取资格)
this.name = name+"--"+count++;


System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
this.notifyAll();
}




//  t3   t4  
public synchronized void out()
{
while(!flag)
try{wait();}catch(Exception e){}//t3(放弃资格) t4(放弃资格)
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
this.notifyAll();
}
}


class Producer implements Runnable
{
private Resource res;


Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set("+商品+");
}
}
}


class Consumer implements Runnable
{
private Resource res;


Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值