在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度。
问题的产生:
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。
问题的处理:
生产者和消费者模式是通过一个容器来解决生产者和消费者之间的强耦合问题。
生产者和消费者不直接通信,而是通过一个阻塞队列来间接的进行通信,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者也不找生产者要数据,而是直接从阻塞队列中去取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者之间的处理能力。
这里有个小经验,一般设计模式解耦问题,都是通过引入一个第三者类,所以学习设计模式的时候,可以以第三者类作为切入点。
基于java实现生产者消费者的具体实例:
现有一种商品,生产者负责生产,消费者负责使用。为了解耦,使用一个缓冲区,相当于一个仓库。代码如下:
import java.util.*;
public class ProducerCustomerTest {
private static final BufferedArea buffer = new BufferedArea();
private static Producer producer = new Producer(buffer);
private static Customer customer = new Customer(buffer);
public static void main(String args[])
{
Thread thread1 = new Thread(producer);
Thread thread2 = new Thread(customer);
thread1.start();
thread2.start();
}
}
//生产者类,生产商品,放进缓冲区
class Producer implements Runnable
{
private BufferedArea bufferedArea = null;
public Producer(BufferedArea buffer)
{
this.bufferedArea = buffer;
}
public void run()
{
for(int i = 0; i < 30; i++)
{
Goods goods = new Goods(i); //生产商品
// System.out.println("生产者生产出商品:" + goods.getNumber());
this.bufferedArea.push(goods); //放入缓冲区
}
}
}
//消费者类,从缓冲区中取出商品
class Customer implements Runnable
{
private BufferedArea bufferedArea = null;
public Customer(BufferedArea buffer)
{
this.bufferedArea = buffer;
}
public void run()
{
for(int i = 0; i < 30; i++)
{
Goods goods = bufferedArea.poll();
// System.out.println("消费者使用商品:" + goods.getNumber());
}
}
}
//管程类,也就是所谓的缓冲区
class BufferedArea
{
private Goods[] goodss = null;
private int count = 0;
public BufferedArea()
{
this.goodss = new Goods[10];
}
//封装函数,缓冲区放入操作
public synchronized void push(Goods goods)
{
if(count == goodss.length) //缓冲区已满,无法放入
this.go_to_wait(); //阻塞
System.out.println("生产者放入仓库商品:" + goods.getNumber());
goodss[count] = goods; //放入产品
count++;
this.notifyAll(); //如果取出商品阻塞,现在将其唤醒
}
//封装函数,缓冲区取出操作
public synchronized Goods poll()
{
if(count == 0) //缓冲区没有商品
this.go_to_wait(); //阻塞等待
count--;
Goods goods = goodss[count];
System.out.println("消费者从仓库取出商品:" + goods.getNumber());
goodss[count] = null;
this.notifyAll(); //如果放入商品阻塞,现在将其唤醒
return goods;
}
private void go_to_wait()
{
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//封装商品类
class Goods
{
private int number = 0;
public Goods(int number)
{
this.number = number;
}
public void setNumber(int number)
{
this.number = number;
}
public int getNumber()
{
return this.number;
}
}
程序测试结果不唯一,自行测试即可!