一.定义
多线程 代码常用的一种数据结构
是一种特殊的队列
二.特性
1,其线程安全
2,带有阻塞特性
a)如果队列为空,执行出对列操作,发生阻塞,直到其他线程往队列中添加元素
b)如果队列为满,执行入队列操作,发生阻塞,,直到其他线程从队列中取走元素
三.存在意义
阻塞队列,最大的意义就是来实现"生产者消费者模型"-----一种多线程编写方式.
四.生产者消费者模型
(一)意义
1.解耦合
比如在一个简单的分布式系统
此时当服务器A和服务器B直接进行信息交互,耦合性较高
1)如果服务器B出现问题,服务器A也会被影响到
2)如果在添加一个C服务器与服务器A交互,服务器A必定要做出代码修改
如果我们使用粗阻塞队列帮我们完成生产者消费者模型,就会变成下面这种情况:
把阻塞队列封装成单独的服务器程序,部署到特定的机器上,这时候把队列称为消息队列
此时,耦合性就会降低
1)如果B出现问题,不会对A产生直接影响,只是没办法处理队列信息,发生阻塞
2)如果后序增加一一个C服务器那么可以直接从队列获取元素,A服务器可以不进行修改
2.削峰填谷
在第一种结构下,一旦客户端发起请求过多,每次A都会把消息立即发给B,如B不如A的硬件设施好,也可能B要操作数据库,承担不了这个信息量,就会挂掉.
但是在引入生产者消费者模型后,就会得到改善
比如:A每分钟处理1000次请求,B也处理1000次请求
削峰:
但是当A这面处理3000次请求时,如果让B也处理3000次请求,那B就会挂掉,但是这是由于存在阻塞对列,B依然可以会处理1000次请求来执行,只不过客户端和服务器A需要等待响应,但好过系统挂掉.
填谷:
当上述情况过去了,A接收到的请求恢复正常,B会逐渐处理队列中的请求
(二)代码使用(BlockingQueue)
标准库中,为阻塞队列提供了基于链表和数组的实现的方式,代码如下:
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.put("123");
queue.put("234");
queue.put("345");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println("运行结束");
}
运行结果: 队列为空时,发生阻塞,并未执行后序代码
(三)自己实现阻塞队列
1)代码实现
class MyblockingQueue{
private String[] data = new String[10];//阻塞队列大小10
//对列起始位置
private volatile int head = 0;
//队列末尾元素位置 的下一个位置
private volatile int tail = 0;
//队列中有效个数
private volatile int size = 0;
private Object object = new Object();
//入队方法
public void put(String elem) throws InterruptedException {
synchronized (object){
//当队列元素满了
while (size==data.length){
System.out.println("等待--->为满");
object.wait();
}
data[tail] = elem;
tail++;
//如果到了数组末尾需要重新置0
if(tail==data.length){
tail = 0;
}
size++;
//解除队列为空的等待
if(size==1){
//System.out.println("解除队列为空的等待");
object.notify();
}
}
}
//出队列
public String take() throws InterruptedException {
synchronized (object){
//如果队列为空
while (size==0){
System.out.println("等待--->为空");
object.wait();
}
String ret = data[head];
head++;
if(head==data.length){
head = 0;
}
size--;
//解除队列为满的等待
if(size<data.length){
//System.out.println("解除队列为满的等待");
object.notify();
}
return ret;
}
}
}
public class Demo2 {
public static void main(String[] args) {
//生产者 消费者,分别用一个线程表示
MyblockingQueue queue = new MyblockingQueue();
//消费者
Thread t1 = new Thread(()->{
while (true){
try {
String result = queue.take();
System.out.println("消费者消费元素:" + result);
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread t2 = new Thread(()->{
int num = 0;
while (true){
try {
System.out.println("生产者生产元素:" + num);
queue.put(num+"");
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
num++;
}
});
t2.start();
t1.start();
}
}
2)执行结果:
3)细节处理
(1)while()interrupt可能会中断wait状态
(2)volatile避免内存可见性(判定,查看)