一、解耦合 削峰填谷
在上图中和,我们可以看到,在A接收到信息后,分为两种情况分别传给B和C去执行.
其中,A做的工作比较简单,每个请求消耗的资源少,主要的工作由B和C去执行,
但是,这时候会出现一种情况 : 如果某一段时间内,传输的信息量暴增,达到了峰值就会导致服务器出现问题,甚至直接挂掉.
比如在以前双十一的时候,购买的用户剧增,就会导致服务器的压力变得非常打.
这时候,就可以用到阻塞队列了.
在A和B、C之间引入一个阻塞队列.
队列没什么业务逻辑,只是存储数据,抗压能力是比较强的.
即使外界的请求出现了峰值,也是由队列来承担峰值请求,B和C仍然是按照之前的速度来运行的.
引入队列,就可以有效的防止B和C出现问题了.
这就是 解耦合 和 削峰填谷.
二、Java标准库提供的阻塞队列
Java标准库提供了现成的阻塞队列数据结构.
ArrayBlockingQueue
BlockingQueue => LinkedBlockingQueue
interface PriorityBlockingQueue
使用put进行入队列.
put是带阻塞功能的,offer是没带阻塞功能的.( 队列满了会返回结果 )
take方法用来出队列,也是带有阻塞功能的.
阻塞队列没有提供带有阻塞功能的获取队首元素的方法.
三、实现阻塞队列
3.1 先实现普通队列
private String[] elem = null;
private int head = 0;
private int last = 0;
private int size = 0;
private Object locker = new Object();
public MyBlockingQueue(int capcity){
this.elem = new String[capcity];
}
public void put(String str) throws InterruptedException{
if(size>=elem.length){
//不插入
}
elem[last]=str;
last++;
if(last>= elem.length){
last=0;
}
size++;
}
public String take() throws InterruptedException{
String elems = null;
if(size==0){
//无法出队列
}
elems = elem[head];
if(head>=elem.length){
head=0;
}
size--;
return elems;
}
这就是阻塞队列基础版的阻塞队列.
3.2 加上线程安全
为了防止多线程时出现线线程安全,我们把整个方法都进行加锁.
public void put(String str) throws InterruptedException{
synchronized(locker) {
if (size >= elem.length) {
//不插入
}
elem[last] = str;
last++;
if (last >= elem.length) {
last = 0;
}
size++;
}
}
public String take() throws InterruptedException{
synchronized (locker) {
String elems = null;
if (size == 0) {
//无法出队列
}
elems = elem[head];
if (head >= elem.length) {
head = 0;
}
size--;
return elems;
}
}
3.3 加上阻塞功能
最后,加上阻塞功能,使代码在执行的时候
1.入队列时,队列为满则阻塞
2.出队列时,队列为空则阻塞
public void put(String str) throws InterruptedException{
synchronized(locker) {
while(size >= elem.length) {
locker.wait();
}
elem[last] = str;
last++;
if (last >= elem.length) {
last = 0;
}
size++;
locker.notify();
}
}
public String take() throws InterruptedException{
String elems = null;
synchronized (locker) {
while(size == 0) {
locker.wait();
}
elems = elem[head];
if (head >= elem.length) {
head = 0;
}
size--;
locker.notify();
}
return elems;
}
基于这个阻塞队列,就可以写一个 " 生产者消费者 "模型了. -> 最核心的部分仍然是阻塞队列.
-> 使用synchronized 和wait/notify 达到 线程安全 & 阻塞.
往往是多个生产者多个消费者.
这里的生产者和消费者往往不仅仅是一个线程,也可能是一个独立的服务器程序,甚至是一组服务器程序.