阻塞队列(BlockingQueue)是一个支持两个附加操作的线程安全的队列,这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空;当队列满时,存储元素的线程会等待队列可用。
面向接口编程,当然要先定义一个接口了:
/**
* @description: 阻塞队列
* @author: 張青云
* @create: 2021-12-23 10:45
**/
public interface MyBlockQueue<E> {
/**
* 向阻塞队列中插入一个元素,如果队列满了则阻塞
*/
void put(E obj) throws InterruptedException;
/**
* 从阻塞队列中获取一个元素,如果队列中没有则阻塞
*/
E take() throws InterruptedException;
}
这里我使用链表来实现了一个阻塞队列:
/**
* @description: 链表实现的阻塞队列
* @author: 張青云
* @create: 2021-12-31 21:38
**/
public class MyLinkedBlockQueue<E> implements MyBlockQueue<E> {
/**
* 队列的容量
*/
private final int capacity;
/**
* 当前队列中的元素个数
*/
private AtomicInteger count;
// 用于添加元素时的锁,即队列尾部的锁
private ReentrantLock putLock = new ReentrantLock();
// 阻塞队列满时的等待队列
private Condition fullCondition = putLock.newCondition();
// 用于获取元素时的锁,即队列头部的锁
private ReentrantLock takeLock = new ReentrantLock();
// 阻塞队列空时的等待队列
private Condition emptyCondition = takeLock.newCondition();
// 链表头结点,有效数据为null
private Node<E> head = new Node<>();
// 链表最后一个结点
private Node<E> tail = head;
public MyLinkedBlockQueue(int capacity) {
this.capacity = capacity;
this.count = new AtomicInteger(0);
}
@Override
public void put(E obj) throws InterruptedException {
int c = -1;
// 创建结点
Node<E> node = new Node<>(obj);
// 加锁
putLock.lockInterruptibly();
try {
// 如果队列已经满了,则阻塞在这里
while (count.get() == capacity) { // 注意:这里应该使用while
fullCondition.await();
}
// 将结点添加到链表中
tail.next = node;
tail = tail.next;
c = count.getAndIncrement();
// 如果有线程正在阻塞在获取元素上,则唤醒它
if(c == 0) {
signalNotEmpty();
}
if (count.get() < capacity) {
fullCondition.signal();
}
} finally {
putLock.unlock();
}
}
@Override
public E take() throws InterruptedException {
int c = -1;
E res;
// 加锁
takeLock.lockInterruptibly();
try {
// 如果队列为空则阻塞
while (count.get() == 0) {
emptyCondition.await();
}
// 获取队头元素
Node<E> h = head;
Node<E> node = h.next;
head = node;
res = node.val;
head.val = null;
c = count.getAndDecrement();
// 如果有线程正在阻塞在添加元素上,则唤醒它
if (c == capacity) {
signalNotFull();
}
if (count.get() > 0) {
emptyCondition.signal();
}
} finally {
takeLock.unlock();
}
return res;
}
/**
* 通知获取元素的线程有新增元素
*/
private void signalNotEmpty() {
takeLock.lock();
try {
// 唤醒一个线程
emptyCondition.signal();
} finally {
takeLock.unlock();
}
}
private void signalNotFull() {
putLock.lock();
try {
fullCondition.signal();
} finally {
putLock.unlock();
}
}
static class Node<E> {
E val;
Node<E> next;
public Node() {
}
public Node(E val) {
this.val = val;
}
}
}