这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战
前言
面试的老生常谈就是设计模式,从设计模式可以延伸到各种实战业务,但一般我们都会问几个常用的,单例、工厂这些模式,把话题引申到我们擅长的领域,当被问到单例的时候,我们可以说我们在业务中常用的生产者消费者模式~
生产者消费者模式
生产消费者模式并不是GOF提出的23种设计模式之一,23种设计模式是建立在面向对象的基础上,但其实面向过程的编程中也有很多高效的设计模式,生产者消费者模式便是其中之一,它是我们编程中最常用的一种设计模式。
在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。
单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。
实现(使用wait()方法和notify()方法实现生产者消费者模式)
- 缓冲区(队列形式):
- 参数:
- maxSize:队列容量的最大程度
- storage:定义一个LinkedList去实现队列装载、
- 方法:
- put():判断缓冲区容量是否最大值,如果是则调用wait()方法,陷入阻塞;反之,插入队列,并唤醒线程;
- take():判断缓冲区容量是否为0,如果是则调用wait()方法,陷入阻塞;反之,弹出队列,并唤醒线程
- 参数:
- 生产者:
- 构造缓冲区函数
- 继承Runnable接口并重写Run方法,在里面遍历调用put()
- 消费者:
- 构造缓冲区函数
- 继承Runnable接口并重写Run方法,在里面遍历调用take()
- 主线程Main()方法:
- 构造缓冲区、生产者、消费者方法
- 构造两个线程并传入生产者、消费者。
- 启动两个线程
public class ProducerConsumerModel {
public static void main(String[] args) {
EventStorage eventStorage = new EventStorage();
Producer producer = new Producer(eventStorage);
Consumer consumer = new Consumer(eventStorage);
Thread thread = new Thread(producer);
Thread thread1 = new Thread(consumer);
thread.start();
thread1.start();
}
}
//生产者
class Producer implements Runnable{
private EventStorage eventStorage;
public Producer(EventStorage eventStorage) {
this.eventStorage = eventStorage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
eventStorage.put();
}
}
}
//消费者
class Consumer implements Runnable{
private EventStorage eventStorage;
public Consumer(EventStorage eventStorage) {
this.eventStorage = eventStorage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
eventStorage.take();
}
}
}
//定义一个队列
class EventStorage{
private int maxSize;
private LinkedList<Date> storage;
public EventStorage() {
this.maxSize = 10;
this.storage = new LinkedList<>();
}
public synchronized void put(){
while (storage.size()==maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date());
System.out.println("当前仓库容量为"+storage.size());
notify();
}
public synchronized void take(){
while(storage.size() == 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.poll();
System.out.println("已取出,当前容量为"+storage.size());
notify();
}
}
总结
在实际的业务中,信息服务器要接收大批量的客户端请求,原来那种串行化的处理,根本无法及时处理客户端请求,造成信息服务器大量请求堆积,导致丢包异常严重。之后就采用了生产者消费者模式,在业务请求与业务处理间,建立了一个List 类型的缓冲区,服务端接收到业务请求,就往里扔,然后再去接收下一个业务请求,而 多个业务处理线程,就会去缓冲区里取业务请求处理。这样就大大提高了服务器的相应速度。