java多线程之生产者-消费者模型
模型图解
首先来看一张图,明白消费者-生产者里都有哪些角色。
数据单元
每次生产者放到缓冲区的,就是一个数据单元;每次消费者从缓冲区取出的,也是一个数据单元。此处的数据单元为一个product
缓存区
此处指的是仓库
生产者
生产产品
消费者
消费产品
模型意义
解 耦
假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
支持并发(concurrency)
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体(常见并发类型有进程和线程两种,后面的帖子会讲两种并发类型下的应用)。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。
支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
代码实现
product(数据单元)
//一个javabean,用来存储信息
class Product {
private int id;// 产品id
private String name;// 产品名称
public Product(int id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return "(产品ID:" + id + " 产品名称:" + name + ")";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
缓存(Storage)
class Storage {
// 仓库容量为10
private Product[] products = new Product[10];
private int top = 0;
// 生产者往仓库中放入产品
public synchronized void push(Product product) {
while (top == products.length) {
try {
System.out.println("producer wait");
wait();//仓库已满,等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//把产品放入仓库
products[top++] = product;
System.out.println(Thread.currentThread().getName() + " 生产了产品"
+ product);
System.out.println("producer notifyAll");
notifyAll();//唤醒等待线程
}
// 消费者从仓库中取出产品
public synchronized Product pop() {
while (top == 0) {
try {
System.out.println("consumer wait");
wait();//仓库空,等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//从仓库中取产品
--top;
Product p = new Product(products[top].getId(), products[top].getName());
products[top] = null;
System.out.println(Thread.currentThread().getName() + " 消费了产品" + p);
System.out.println("comsumer notifyAll");
notifyAll();//唤醒等待线程
return p;
}
}
生产者(producer)
class Producer implements Runnable {
private Storage storage;
public Producer(Storage storage) {
this.storage = storage;
}
//生产10个产品
@Override
public void run() {
int i = 0;
Random r = new Random();
while(i<10)
{
i++;
Product product = new Product(i, "电话" + r.nextInt(100));
storage.push(product);
}
}
}
消费者(consumer)
class Consumer implements Runnable {
private Storage storage;
public Consumer(Storage storage) {
this.storage = storage;
}
//每一个线程都会从仓库中取10个产品
public void run() {
int i = 0;
while(i<10)
{
i++;
storage.pop();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
main()
public static void main(String[] args) throws InterruptedException {
Storage storage = new Storage();
Thread consumer1 = new Thread(new Consumer(storage));
consumer1.setName("消费者1");
Thread consumer2 = new Thread(new Consumer(storage));
consumer2.setName("消费者2");
Thread producer1 = new Thread(new Producer(storage));
producer1.setName("生产者1");
Thread producer2 = new Thread(new Producer(storage));
producer2.setName("生产者2");
producer1.start();
producer2.start();
Thread.sleep(1000);
consumer1.start();
consumer2.start();
}