Java 如果已满,则从ArrayBlockingQueue中逐出对象
我使用的是ArrayBlockingQueue,但有时它会变满,并阻止向其中添加其他对象 我想做的是删除队列中最旧的对象,然后在ArrayBlockingQueue满时添加另一个对象。我需要ArrayBlockingQueue像番石榴驱逐队列,但线程安全。我打算扩展ArrayBlockingQueue并覆盖offer(E)方法,如下所示:Java 如果已满,则从ArrayBlockingQueue中逐出对象,java,multithreading,guava,blockingqueue,Java,Multithreading,Guava,Blockingqueue,我使用的是ArrayBlockingQueue,但有时它会变满,并阻止向其中添加其他对象 我想做的是删除队列中最旧的对象,然后在ArrayBlockingQueue满时添加另一个对象。我需要ArrayBlockingQueue像番石榴驱逐队列,但线程安全。我打算扩展ArrayBlockingQueue并覆盖offer(E)方法,如下所示: public class MyArrayBlockingQueue<E> extends ArrayBlockingQueue<E>
public class MyArrayBlockingQueue<E> extends ArrayBlockingQueue<E> {
// Size of the queue
private int size;
// Constructor
public MyArrayBlockingQueue(int queueSize) {
super(queueSize);
this.size = queueSize;
}
@Override
synchronized public boolean offer(E e) {
// Is queue full?
if (super.size() == this.size) {
// if queue is full remove element
this.remove();
}
return super.offer(e);
} }
公共类MyArrayBlockingQueue扩展了ArrayBlockingQueue{
//队列的大小
私有整数大小;
//建造师
公共MyArrayBlockingQueue(int queueSize){
超级(队列大小);
this.size=队列大小;
}
@凌驾
同步公共布尔报价(E){
//排满了吗?
if(super.size()==此.size){
//如果队列已满,请删除元素
这个。删除();
}
返回超级报价(e);
} }
上述方法行吗?还是有更好的方法
谢谢当你说“它已满并阻止添加其他对象”时,这是否意味着它足以确保可以随时添加对象?如果这是真的,您可以简单地切换到一个无界队列,例如。但请注意与阵列锁定队列相比的差异:
链接队列通常比基于阵列的队列具有更高的吞吐量,但在大多数并发应用程序中性能不太可预测
您可以找到JDK队列实现的概述。您的MyArrayBlockingQueue
不会覆盖BlockingQueue.offer(E,long,TimeUnit)
或BlockingQueue.poll(long,TimeUnit)
。您真的需要具有“阻塞”功能的队列吗?如果您不这样做,则可以使用以下方法创建一个由支持的线程安全队列:
对于逐出阻塞队列,我发现您建议的实现存在一些问题:
remove()
如果队列为空,则可能引发异常。您的offer
方法标记为synchronized
,但是poll
、remove
等不是这样的,因此另一个线程可能会在调用size()
和remove()
之间耗尽您的队列。我建议改用不会引发异常的poll()
您对offer
的调用仍然可能返回false
(即,不“添加”元素),因为另一个竞争条件,在检查大小和/或删除元素以减小大小之间,另一个线程会添加一个填充队列的元素。我建议对offer
的结果使用循环关闭,直到返回true
(见下文)
调用size()
我相信以下实施将为您带来您想要的:
public class EvictingBlockingQueue<E> extends ArrayBlockingQueue<E> {
public EvictingBlockingQueue(int capacity) {
super(capacity);
}
@Override
public boolean offer(E e) {
while (!super.offer(e)) poll();
return true;
}
@Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
while (!super.offer(e, timeout, unit)) poll();
return true;
}
}
公共类退出BlockingQueue扩展了ArrayBlockingQueue{
公共逐出阻塞队列(整数容量){
超级(容量);
}
@凌驾
公共布尔报价(E){
而(!super.offer(e))poll();
返回true;
}
@凌驾
公共布尔提供(E、长超时、时间单位)抛出InterruptedException{
而(!super.offer(e,timeout,unit))poll();
返回true;
}
}
请注意,如果在对super.offer(E)
的两次调用之间,另一个线程删除一个元素,则此实现可能会不必要地删除该元素。这对我来说似乎是可以接受的,但我并没有看到一种切实可行的解决方法(ArrayBlockingQueue.lock
是包私有的,java.util.concurrent
是禁止的包,所以我们不能在那里放置一个实现来访问和使用锁等)。Hi mfulton26。我的错误是,我仍然想要一个具有阻塞功能的队列。你是说一个Queues.synchronizedQueue(executingQueue.create(maxSize));会有阻塞吗?@user1982350我已经更新了我的答案,以解决驱逐阻塞队列的需要。谢谢mfulton26。我要试一试。我发现令人惊讶的是,没有人编写一个BlockingQueue,在一定时间后自动从自身移除对象。理想情况下,我只需要一个ArrayBlockingQueue来跟踪对象在队列中的时间。一旦过了一定的时间,就把旧东西扔掉。我会尝试你的解决方案。我想到了,但我也在努力避免对象在队列中停留太长时间。这就是为什么我要删除队列头部的对象,以便为要添加到尾部的下一条消息腾出空间。我需要在队列已满时逐出一条消息,并保留对ArrayBlockingQueue的阻塞。看来番石榴驱逐队可以完成这项工作。
public class EvictingBlockingQueue<E> extends ArrayBlockingQueue<E> {
public EvictingBlockingQueue(int capacity) {
super(capacity);
}
@Override
public boolean offer(E e) {
while (!super.offer(e)) poll();
return true;
}
@Override
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
while (!super.offer(e, timeout, unit)) poll();
return true;
}
}