黑马程序员技术交流社区
标题:
生产者与消费者问题
[打印本页]
作者:
itheima_llt
时间:
2015-4-11 22:37
标题:
生产者与消费者问题
生产者消费者问题
一、先处理只有1个生产者和1个消费者的情况
二、再处理2个生产者和2个消费者的情况
对于一、
步骤:
1 建立一个资源类,包含成员变量(商品名称,商品编号、监视器)
和方法(设置商品名称和商品编号)
2 建立生产者类,实现Runnable接口,覆盖run方法
3 建立消费者类,实现Runnable接口,覆盖run方法
//1个消费者线程和1个生产者线程
class Resource
{
private String name;//商品名称
private int count=1;//商品编号
private boolean flag = false;//监视器
//设置商品名称,编号自动加1
public synchronized void set(String name)
{
if(flag)//如果资源监视器为真,那么调用本方法的对象等待
try
{
this.wait();
}
catch (Exception e)
{
}
this.name = name;
count++;
System.out.println(Thread.currentThread().getName()+"..."+name+"...生产者...编号:"+count);
flag = true;
this.notify();//唤醒线程池中的第一个线程
}
//获取商品名称和编号
public synchronized void get()
{
if(!flag)//如果资源监视器为假,那么调用本方法的对象等待
try
{
this.wait();
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"..."+name+"....消费者.........编号:"+count);
flag = false;
this.notify();//唤醒线程池中的第一线程
}
}
class Producer implements Runnable
{
private Resource r;
//利用传递引用类型变量和构造函数避免造成初始化对象不唯一
Producer(Resource r)
{
this.r =r;
}
public void run()
{
while(true)
r.set("商品");
}
}
class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
r.get();
}
}
class MyProducerConsumerDemo
{
public static void main(String[] args)
{
//建立资源对象
Resource r =new Resource();
//建立生产者对象
Producer p =new Producer(r);
//建立消费者对象
Consumer c = new Consumer(r);
//建立生产者线程
Thread tp1 = new Thread(p);
//建立消费者线程
Thread cp1 = new Thread(c);
//启动生产者线程
tp1.start();
//启动消费者线程
cp1.start();
//简化代码
//new Thread(new Producer(r)).start();
//new Thread(new Consumer(r)).start();
}
}
复制代码
//两个生产者和两个消费者线程
class Resource
{
private String name;//商品名称
private int count=1;//商品编号
private boolean flag = false;//监视器
//设置商品名称,编号自动加1
public synchronized void set(String name)
{
//if(flag)//如果资源监视器为真,那么调用本方法的对象等待
while(flag)
try
{
this.wait();
}
catch (Exception e)
{
}
this.name = name;
count++;
System.out.println(Thread.currentThread().getName()+"..."+name+"...生产者...编号:"+count);
flag = true;
this.notifyAll();//唤醒线程池中的第一个线程
}
//获取商品名称和编号
public synchronized void get()
{
//if(!flag)//如果资源监视器为假,那么调用本方法的对象等待
while(!flag)
try
{
this.wait();
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"..."+name+"....消费者.........编号:"+count);
flag = false;
this.notifyAll();//唤醒线程池中的第一线程
}
}
class Producer implements Runnable
{
private Resource r;
//利用传递引用类型变量和构造函数避免造成初始化对象不唯一
Producer(Resource r)
{
this.r =r;
}
public void run()
{
while(true)
r.set("商品");
}
}
class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
r.get();
}
}
class MyProducerConsumerDemo
{
public static void main(String[] args)
{
//建立资源对象
Resource r =new Resource();
//建立生产者对象
Producer p =new Producer(r);
//建立消费者对象
Consumer c = new Consumer(r);
//建立生产者线程
Thread tp1 = new Thread(p);
Thread tp2 = new Thread(p);
//建立消费者线程
Thread cp1 = new Thread(c);
Thread cp2 = new Thread(c);
//启动生产者线程
tp1.start();
tp2.start();
//启动消费者线程
cp1.start();
cp2.start();
}
}
复制代码
运行结果出现:
生产一次,消费2次的情况。
Thread-1...商品...生产者...编号:359
Thread-3...商品....消费者.........编号:359
Thread-2...商品....消费者.........编号:359
生产2次,消费1次的情况。
Thread-1...商品...生产者...编号:3424
Thread-0...商品...生产者...编号:3425
Thread-3...商品....消费者.........编号:3425
这说明,原来在1个生产者和1个消费者安全
但在2个生产者和2个消费者就不安全了。
为什么会这样呢??
因为在用if语句判断的时候,当线程被唤醒后,它并没有再判断flag,
而是直接执行下一条语句,所以我们可以把if改成while。
> if(flag)//如果资源监视器为真,那么调用本方法的对象等待
改成while(flag)的时候,运行结果为:
Thread-0...商品...生产者...编号:2
Thread-3...商品....消费者.........编号:2
Thread-1...商品...生产者...编号:3
Thread-3...商品....消费者.........编号:3
Thread-0...商品...生产者...编号:4
4个线程全部处于睡眠状态,不再打印。
这又是因为睡眠呢??
原因是notify唤醒的都是线程池中的第一个线程,
这就导致了被唤醒的线程不一定是对方的线程。
而当唤醒的是本方线程时候,线程就全部陷入了等待。
该怎么解决呢??
可以用notifyAll();
运行结果显示安全问题被解决!
小结:
在多个生产者和多个消费者的情况下,
用while+notifyAll();
作者:
itheima_llt
时间:
2015-4-12 21:52
{:3_54:}自己顶一下!
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2