![](/img/trans.png)
[英]How to check if ArrayBlockingQueue is locked or queue element currently processed by thread?
[英]ArrayBlockingQueue in which queue head is removed if the queue is full while adding an element
我正在尝试编写一个简单的队列,如ArrayBlockingQueue,如果添加元素时队列已满,则将删除队列的头部。 该类应仅具有以下公共方法
有人可以查看下面的代码,让我知道是否有更好的方法吗?
public class CircularArrayNonBlockingQueue<E> {
private ArrayBlockingQueue<E> blockingQueue;
public CircularArrayNonBlockingQueue(int size) {
blockingQueue = new ArrayBlockingQueue<>(size);
}
public synchronized int size() {
return blockingQueue.size();
}
public synchronized void add(E element) {
if(blockingQueue.remainingCapacity() <= 0) {
blockingQueue.poll();
}
blockingQueue.add(element);
}
public synchronized E poll() {
return blockingQueue.poll();
}
}
编辑根据评论中的讨论,我不需要使所有方法都synchronized
。 更新后的代码如下所示-
public class CircularNonBlockingQueue<E> {
private final ArrayBlockingQueue<E> blockingQueue;
public CircularNonBlockingQueue(int size) {
blockingQueue = new ArrayBlockingQueue<>(size);
}
public int size() {
return blockingQueue.size();
}
public synchronized void add(E element) {
if(blockingQueue.remainingCapacity() <= 0) {
blockingQueue.poll();
}
blockingQueue.add(element);
}
public E take() throws InterruptedException {
return blockingQueue.take();
}
}
拥有线程安全的后端集合不一定可以创建正确的程序。 当仅synchronized
您的add
方法时, take()
方法可能会并发运行,因此有可能在add
执行if(blockingQueue.remainingCapacity() <= 0)
测试之后,同时运行的take()
会删除一个元素,因此add
的poll()
可能会不必要地删除元素。 与add()
在take()
之前完成的情况有明显的不同,因为使用线程将收到不同的项。 换句话说,效果似乎是有时add
不会删除最旧的项目,而是删除第二个最旧的项目。
在另一方面,如果使用synchronized
您所有的方法一致,没有必要有一个线程安全的后端收集:
import java.util.ArrayDeque;
public class CircularBlockingQueue<E> {
private final ArrayDeque<E> blockingQueue;
private final int maxSize;
public CircularBlockingQueue(int size) {
if(size<1) throw new IllegalArgumentException("size == "+size);
blockingQueue = new ArrayDeque<>(size);
maxSize = size;
}
public synchronized int size() {
return blockingQueue.size();
}
public synchronized void add(E element) {
if(blockingQueue.size() == maxSize) {
blockingQueue.poll();
}
blockingQueue.add(element);
notify();
}
public synchronized E take() throws InterruptedException {
while(blockingQueue.isEmpty()) wait();
return blockingQueue.remove();
}
}
但是,如果您可以对最旧的元素使用较弱的保证,则可以使用BlockingQueue
并且不需要任何synchronized
:
public class CircularBlockingQueue<E> {
private final ArrayBlockingQueue<E> blockingQueue;
public CircularBlockingQueue(int size) {
blockingQueue = new ArrayBlockingQueue<>(size);
}
public int size() {
return blockingQueue.size();
}
public void add(E element) {
while(!blockingQueue.offer(element)) {
blockingQueue.poll();
}
}
public E take() throws InterruptedException {
return blockingQueue.take();
}
}
必须指出的是,这些解决方案都不提供“公平性”。 因此,如果生产者线程和消费者线程的数量比队列的容量大,则存在生产者重复删除项目而不重新激活在take()
阻塞的线程的风险。 因此,您应始终确保具有足够大的容量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.