目录
一.什么是阻塞队列(BlockingDeque)
二.阻塞队列有什么用?
三.运用阻塞队列来实现一个最简单的生产者消费者
四.模拟实现阻塞队列
一.什么是阻塞队列(BlockingDeque)
既然叫做阻塞队列,那么他就满足两个特性
1.队列:先进先出
2.阻塞:空了不让出,满了不让进
- (1)如果队列为空,尝试出队列,就会出现阻塞,阻塞到队列不为空为止;
- (2)如果队列满了,尝试入队列,就会出现阻塞,阻塞到队列不为满为止。
二.阻塞队列有什么用?
如果按照课本上的理论来说,就是解耦合,保证两个对象不是强耦合的关系
举一个现实中的例子
"消息队列"
如果我们发送消息没有使用阻塞队列,只是两个对象直接交互的的话是这样
但是如果一旦A或者B某一方发生了错误之后
就可能导致两个都崩溃掉
所以为了防止这种强耦合的情况发生我们引入一个阻塞队列
好处:
1.即使A或者B某一方崩溃了,那么也不会导致另一方也崩溃(降低耦合)
2.如果在某个时间段内A或者B某一方的数据量激增/极减,但是通过阻塞队列,能保证读取数据不变,保证程序运行的稳定性(削峰填谷)
三.运用阻塞队列来实现一个最简单的生产者消费者
创建两个线程,一个只生产,另一个只消费
public class demo7 {
public static BlockingDeque blockingDeque = new LinkedBlockingDeque();
public static void main(String[] args) {
//t1是生产者
Thread t1 = new Thread(()->{
for (int i = 0; i < 5; i++) {
//生产
blockingDeque.add(i);
System.out.println("我生产了"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//t2是消费者
Thread t2 = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
//消费
System.out.println("我消费了"+blockingDeque.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
t2.start();
}
}
运行结果
四.模拟实现阻塞队列
第一步实现一个环形队列
第二部对进队列和出队列进行加锁和解锁
public class MyBlockingDeque {
//设置一个环形队列
private int[] arry = new int[100];
private int size = 0 ;
private int head = 0;
private int tail = 0;
private Object lock = new Object();
public void put(int key) throws InterruptedException {
synchronized (lock){
//如果队列满了就加锁,不让进队列
if(size == arry.length){
lock.wait();
}
arry[tail] = key;
tail++;
//环形队列
if(tail >= arry.length){
tail = tail-arry.length;
}
size++;
//注意解锁免得不能出队列
lock.notify();
}
}
public int tack() throws InterruptedException {
synchronized (lock){
//如果队列为空,不让出队列,加锁
if(size == 0){
lock.wait();
}
int ret = arry[head];
head++;
//环形队列
if(head > arry.length){
head = head -arry.length;
}
size--;
//注意解锁,免得不能入队列
lock.notify();
return ret;
}
}
}