目录
一.是什么?
阻塞队列是一种特殊的队列,也是遵循队列的基本特点,先进先出,但是它具有阻塞的功能。
阻塞情形
1)当队列为空时,执行出队列操作时,会发生阻塞,阻塞到另外的线程向队列中添加素为止。
2)当队列满时,执行入队列操作时,会发生阻塞,阻塞到另外的线程向队列中添加元为止。
二.标准库BlockingQueue的使用
首先,BlockingQueue是一个interface,其继承queue。BlockingQueue的实现类有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、 SynchronousQueue、DelayQueue(延时队列)。
1.put和take方法
BlockingQueue的主要的方法是put和take,put为向队列中放入元素,take为向队列取元素,这两个动作都遵循"先入后出"的原则。
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>();
blockingQueue.put(1);
System.out.println(blockingQueue.take());
}
2.实现生产者消费者模型
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>();
Thread customer = new Thread(()->{
while(true){
try {
Integer ret = blockingQueue.take();
System.out.println("消费者"+ret);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
customer.start();
Thread producter = new Thread(()->{
int count = 0;
while(true){
try {
blockingQueue.put(count);
System.out.println("生产者"+count);
Thread.sleep(500);
count++;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
producter.start();
}
三.实现阻塞队列(基于数组)
使用数组的话,只需要两个头尾指针来标记队头和对尾,并使用size变量来记录当前队列的数据个数。
代码如下:
class myBlockingQueue {
private Integer[] arr = null;
private int head = 0;
private int tail = 0;
private int size = 0;
public myBlockingQueue() {
this.arr = new Integer[20];
}
public myBlockingQueue(int n) {
this.arr = new Integer[n];
}
public synchronized void put(Integer value) throws InterruptedException {
while (size == arr.length) {
this.wait();
}
arr[tail] = value;
tail++;
if (tail >= arr.length) {
tail = 0;
}
size++;
this.notify();
}
public synchronized Integer take() throws InterruptedException {
while (size == 0) {
this.wait();
}
int ret = arr[head];
head++;
if (head >= arr.length) {
head = 0;
}
size--;
this.notify();
return ret;
}
}
注意点:
1️⃣.由于put和take操作要对数组进行读写,那么在多线程环境下,就会涉及到线程安全问题,使用synchronized加锁,防止bug。
2️⃣.在put时,当size和数组长度相同时,线程等待;在take时,当size为0时,线程等待。在每次调用put和take后,都调用notify,这样就实现了当take等待时,put一个元素,那么take解锁,put等待时同理。
3️⃣.由于每个wait被唤醒后,判断语句可能在当前仍然满足,需要继续等待,使用while避免此问题。
以上就是本文的全部内容了。