生产者-消费者模式在系统交互方面,有几个特点:
1、系统解耦
2、解决并发问题
3、不需要关心对方系统何时处理数据,处理结果如何
下面用几个简单例子逐步说明。
简单例子
假设有两个系统,A系统和B系统,B系统需要依赖A系统产生的数据,也就是说,A系统产生数据后,必须把数据扔给B系统。
这个时候,可以让B系统提供一个方法,比如说提供一个http接口sendData()
,然后A系统直接调用即可。
这种方案在流量不大的情况下,完全没问题的,但是如果系统并发量大的情况下,每次A系统同步调用B系统的sendData()接口时,就会被阻塞住,如果sendData方法处理的很慢,那么会直接影响A系统的吞吐量的。
因此最好能异步的调用B系统的接口,然后A系统可以立刻返回,继续处理其他事情。
可以直接使用JAVA的线程池技术,new一个线程调用B系统的接口,达到异步调用的目的。
这样的话,A系统就只管发送数据了,无需理会B系统接口的处理速度如何,也不会被B系统的接口阻塞住。但是此时还是有两个问题:
1、B系统此时需要做一些应付大并发量的处理,因为面对A系统的狂轰滥炸,B系统可能处理不过来的。
2、A系统和B系统还是耦合了。因为A系统还是直接调用B系统接口,直接交互的。
有没有更好的方案,双方既能处理并发,同时两个系统之间又无需耦合呢?答案是使用生产者-消费者模式。
生产者-消费者模式
生产者-消费者模式通过引入一个阻塞队列这个第三方组件来做到解耦和处理并发。
生产者只需要往队列里面塞数据,消费者只需要从队列中读取数据,生产者再也无需关注消费者处理数据的速度是如何了。生产者和消费者已经是完全独立的了。
利用某些队列特性,当生产者速度太快的话,数据超过了队列的最大阀值,那么可以自动阻塞住生产者(当然也可以设置线程阻塞的超时时间,防止消费者挂掉了,一直不处理队列中的数据,生产者),一直等到消费者先消费一些数据。
进一步思考
之前写过一篇ThreadPoolExecutor简单介绍介绍了JAVA线程池的一些基本用法,ThreadPoolExecutor也利用了生产者-消费者模式的思想,只不过
ThreadPoolExecutor是有必要的时候才使用队列,性能是比上面的直接使用队列的方式性能要高很多的。实际操作中也可以借鉴这种做法。