在大型电商网站中,他们的服务或者应用解耦之后,是通过消息队列在彼此间通信的。消息队列和应用之间的架构关系就是生产者消费者模型。
生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。生产消费者模式如下图。
在日益发展的服务类型中,譬如注册用户这种服务,它可能解耦成好几种独立的服务(账号验证,邮箱验证码,手机短信码等)。它们作为消费者,等待用户输入数据,在前台数据提交之后会经过分解并发送到各个服务所在的url,分发的那个角色就相当于生产者。消费者在获取数据时候有可能一次不能处理完,那么它们各自有一个请求队列,那就是内存缓冲区了。做这项工作的框架叫做消息队列。
生产者消费者模型的实现
生产者是一堆线程,消费者是另一堆线程,内存缓冲区可以使用List数组队列,数据类型只需要定义一个简单的类就好。关键是如何处理多线程之间的协作。这其实也是多线程通信的一个范例。
在这个模型中,最关键就是内存缓冲区为空的时候消费者必须等待,而内存缓冲区满的时候,生产者必须等待。其他时候可以是个动态平衡。值得注意的是多线程对临界区资源的操作时候必须保证在读写中只能存在一个线程,所以需要设计锁的策略。
基于ReentrantLock的多路通知实现生产者消费者模型:
共享缓冲区DataProvide.i和ReentrantLock锁以及生产者类消费者类进行解耦
public class PCDemo {
public static void main(String[] args) throws Exception{
ReentrantLock lock = new ReentrantLock();
Condition conditionPro = lock.newCondition();
Condition conditionCus = lock.newCondition();
Product product = new Product(lock,conditionPro,conditionCus);
Custom custom = new Custom(lock,conditionPro,conditionCus);
for (int i = 0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true)
custom.custom();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true)
product.product();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}
class DataProvide{
public static int i = 0;
}
class Product{
private ReentrantLock lock;
private Condition conditionPro;
private Condition conditionCus;
public Product(ReentrantLock lock,Condition conditionPro,Condition conditionCus){
this.lock = lock;
this.conditionPro = conditionPro;
this.conditionCus = conditionCus;
}
public void product(){
lock.lock();
try {
while (DataProvide.i==1){
conditionPro.await();
}
DataProvide.i=1;
System.out.println("生产了一个");
conditionCus.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
class Custom{
private ReentrantLock lock;
private Condition conditionPro;
private Condition conditionCus;
public Custom(ReentrantLock lock,Condition conditionPro,Condition conditionCus){
this.lock = lock;
this.conditionPro = conditionPro;
this.conditionCus = conditionCus;
}
public void custom(){
lock.lock();
try {
while (DataProvide.i==0){
conditionCus.await();
}
DataProvide.i=0;
System.out.println("消费了一个");
conditionPro.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}