阻塞队列与普通的队列的区别就是当队列为空或者满时处理的逻辑不通,普通队列返回特殊值(比如null,false等等)而阻塞队列是阻塞当前线程直到队列有元素或者不为空。
这里手写一个阻塞队列。首先定义一个接口:
public interface BlockingQueue<E> {
/**
* 往队列尾部添加一个元素,当队列满时阻塞当前线程
* @param e
*/
void put(E e);
/**
* 从队列首部取走一个元素,当队列为空时阻塞当前线程
* @return
*/
E get();
// 返回队列中元素的数量
int size();
}
下面我们使用两种方式实现它。
1、基于synchronized+wait+notify
public class SBlockingQueue<E> implements BlockingQueue<E> {
//基本参数与数据容器
private final static int DEFAULT_MAX_COUNT = 10;
private final int maxCount;
private final ArrayDeque<E> blockingQueue;
public SBlockingQueue() {
this(DEFAULT_MAX_COUNT);
}
public SBlockingQueue(int size) {
blockingQueue = new ArrayDeque<>(size);
maxCount = size;
}
@Override
public void put(E e) {
synchronized (blockingQueue) {
while (blockingQueue.size() == maxCount) {
try {
System.out.println("队列满了,等待消费数据");
blockingQueue.wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
blockingQueue.add(e);
blockingQueue.notifyAll();
}
}
@Override
public E get() {
synchronized (blockingQueue) {
while (blockingQueue.size() == 0) {
try {
System.out.println("队列中暂时还没数据,等待生产数据");
blockingQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
blockingQueue.notifyAll();
return blockingQueue.removeFirst();
}
}
@Override
public int size() {
return blockingQueue.size();
}
}
2、基于Lock锁
public class LBlockingQueue<E> implements BlockingQueue<E> {
//基本参数与数据容器
private final static int DEFAULT_MAX_COUNT = 10;
private final int maxCount;
private final ArrayDeque<E> blockingQueue;
//锁
private Lock lock = new ReentrantLock();
private final Condition isNull = lock.newCondition();
private final Condition isFull = lock.newCondition();
public LBlockingQueue() {
this(DEFAULT_MAX_COUNT);
}
public LBlockingQueue(int size) {
blockingQueue = new ArrayDeque<>(size);
maxCount = size;
}
@Override
public void put(E e) {
try {
lock.lock();
try {
while (blockingQueue.size() >= maxCount) {
System.out.println("队列满了,等待消费数据");
isFull.await();
}
} catch (InterruptedException ex) {
isFull.signal();
ex.printStackTrace();
}
blockingQueue.add(e);
isNull.signal();
} finally {
lock.unlock();
}
}
@Override
public E get() {
try {
lock.lock();
try {
while (blockingQueue.size() == 0) {
System.out.println("队列中暂时还没数据,等待生产数据");
isNull.await();
}
} catch (InterruptedException e) {
isNull.signal();
e.printStackTrace();
}
E res = blockingQueue.removeFirst();
isFull.signal();
return res;
} finally {
lock.unlock();
}
}
@Override
public int size() {
return blockingQueue.size();
}
}