生产者和消费者问题是线程模型中的经典问题,生产者和消费者在同一时间段共用同一个存储空间,这个存储空间是一个缓冲区的仓库,生产者可以将产品放入仓库,消费者可以从仓库中取出产品。 生产者/消费者模型是基于等待/通知机制,主要关注以下几点: 生产者生产的时候消费者不能消费 消费者消费的时候生产者不能生产 缓冲区空时消费者不能消费 缓冲区满时生产者不能生产 主要优点: 解耦。因为多了一个缓冲区,所以生产者和消费者并不直接相互调用,这一点很容易想到,这样生产者和消费者的代码发生变化,都不会对对方产生影响,这样其实就把生产者和消费者之间的强耦合解开,变为了生产者和缓冲区/消费者和缓冲区之间的弱耦合 通过平衡生产者和消费者的处理能力来提高整体处理数据的速度,这是生产者/消费者模型最重要的一个优点。如果消费者直接从生产者这里拿数据,如果生产者生产的速度很慢,但消费者消费的速度很快,那消费者就得占用CPU的时间片白白等在那边。有了生产者/消费者模型,生产者和消费者就是两个独立的并发体,生产者把生产出来的数据往缓冲区一丢就好了,不必管消费者;消费者也是,从缓冲区去拿数据就好了,也不必管生产者,缓冲区满了就不生产,缓冲区空了就不消费,使生产者/消费者的处理能力达到一个动态的平衡。 生产者消费者案例: 1.奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储和获取牛奶的操作 2.生产者(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作 3.消费者(Customer):实现Runnable接口,重写run()方法,调用存储牛奶的操作 4.测试类(SendMilkDemo):里面有main方法,main方法中的代码步骤如下: a.创建奶箱对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 b.创建生产者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 c.创建消费者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 d.创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 这里使用了wait()等待 和 notify()唤醒 方法。 测试类:
package Mymodifier.testcode.src.Thread; public class SendMilkDemo { public static void main(String[] strings) { /* 生产者消费者案例: 1.奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储和获取牛奶的操作 2.生产者(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作 3.消费者(Customer):实现Runnable接口,重写run()方法,调用存储牛奶的操作 4.测试类(SendMilkDemo):里面有main方法,main方法中的代码步骤如下: a.创建奶箱对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 b.创建生产者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 c.创建消费者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 d.创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 */ //创建奶箱对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 Box b = new Box(); //创建生产者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 Producer p = new Producer(b); //创建消费者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 Comsumer c = new Comsumer(b); //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 Thread p2 = new Thread(p,"生产者"); Thread c2 = new Thread(c,"消费者"); //启动线程 p2.start(); c2.start(); } }
奶箱类:
package Mymodifier.testcode.src.Thread;
public class Box
{
//定义一个成员变量,表示第x瓶奶
private int milk;
//创建牛奶状态(默认为false)
private boolean state = false;
//存储牛奶数量(加了同步关键字才能使用wait(等待)和notify/All(唤醒))
public synchronized void put(int milk) {
//如果牛奶状态为true
if(state)
{
//则进入等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.milk = milk;
//如果有牛奶,就消费牛奶
System.out.println("送奶工将第" + this.milk + "瓶放入奶箱");
//牛奶状态设置为true
state = true;
//唤醒全部等待线程
notifyAll();
}
//获取牛奶数量
public synchronized void get() {
//如果牛奶状态为false
if (!state)
{
//则进入等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有牛奶,就生产牛奶
System.out.println("用户拿到第" + this.milk + "瓶奶");
//牛奶状态设置为true
state = false;
//唤醒全部等待线程
notifyAll();
}
}
生产者类(送奶工):
package Mymodifier.testcode.src.Thread;
public class Producer implements Runnable
{
private Box b;
public Producer(Box b)
{
this.b = b;
}
@Override
public void run() {
for(int i = 1; i < 6; i++)
{
b.put(i);
}
}
}
消费者类:
package Mymodifier.testcode.src.Thread;
public class Comsumer implements Runnable {
private Box b;
public Comsumer(Box b)
{
this.b = b;
}
@Override
public void run()
{
while(true)
{
b.get();
}
}
}