阻塞队列
定义:
1)符合先进先出的队列
2)线程安全
3)产生阻塞效果
如果队列为空,尝试出队列就会出现阻塞,阻塞到队列不为空为止
如果队列为满,尝试入队列也会出现阻塞,阻塞到队列不为满为止
BlockingQueue<String> queque = new LinkedBlockingQueue<>();
queue.put("hello");
String s = queue.take();
生产者消费者模型
优点:
1.解耦合
2.能够对请求削峰填谷实际开发中使用到的“阻塞队列”并不是一个简单的数据结构了,而是一个/一组专门的服务器程序,提供的功能也不仅仅是阻塞队列的功能还有数据持久化存储,支持多个数据通道…,这样的队列被称为消息队列
总结生产者消费者模型:
1.直接对方法加锁
2.队列为满或者为空时阻塞
3.放入获取出队列
4.唤醒对应等待
class MyBlockingQueue{
//保存数据的本体
private int[] data = new int[1000];
//有效元素个数
private int size = 0;
//队首元素下标
private int head = 0;
//队尾下标
private int tail = 0;
//专门的锁对象
private Object locker = new Object();
//入队列
public void put(int value) throws InterruptedException {
synchronized (locker){
if(size == data.length){
//队列满了,等待
locker.wait();
}
//把新的元素放到tail位置上
data[tail] = value;
tail++;
if(tail >= data.length){
tail = 0;
}
size++;
//如果入队成功,则队列非空,于是就唤醒take中的阻塞等待
locker.notify();
}
}
public Integer take() throws InterruptedException {
synchronized (locker){
if(size == 0){
//如果队列为空就阻塞
locker.wait();
}
//取出head位置的元素
int ret = data[head];
head++;
if(head >= data.length){
head = 0;
}
size--;
//take成功之后,就唤醒put中的等待
locker.notify();
return ret;
}
}
}
public class 生产者消费者模型 {
private static MyBlockingQueue queue = new MyBlockingQueue();
public static void main(String[] args) {
Thread producer = new Thread(() -> {
int num = 0;
while(true){
try {
System.out.println("生产了:" + num);
queue.put(num);
num++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
Thread customer = new Thread(() ->{
while(true){
try {
int num = queue.take();
System.out.println("消费了:" + num);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
customer.start();
}
}