我目前正在使用ConcurrentLinkedQueue,这样我就可以使用自然顺序FIFO,也可以在线程安全的应用程序中使用它。我需要每分钟记录一次队列的大小,并且考虑到这个集合不能保证大小,并且计算大小的成本是O(N),是否有任何替代的有边界的非阻塞并发队列,我可以使用在获得大小的地方不会是一个昂贵的操作,同时添加/删除操作也不昂贵?
如果没有集合,我需要使用带锁的LinkedList吗?
如果您真的(真的)需要记录您当前正在处理的Queue
的正确当前大小-您需要阻塞。没有别的办法。您可以认为维护单独的LongAdder
字段可能会有所帮助,可能是在ConcurrentLinkedQueue
周围创建自己的接口作为包装器,例如:
interface KnownSizeQueue<T> {
T poll();
long size();
}
和实现:
static class ConcurrentKnownSizeQueue<T> implements KnownSizeQueue<T> {
private final ConcurrentLinkedQueue<T> queue = new ConcurrentLinkedQueue<>();
private final LongAdder currentSize = new LongAdder();
@Override
public T poll() {
T result = queue.poll();
if(result != null){
currentSize.decrement();
}
return result;
}
@Override
public long size() {
return currentSize.sum();
}
}
我只是鼓励您在接口中再添加一个方法,如remove
,并尝试对代码进行推理。您将很快意识到,这样的实现仍然会给您一个错误的结果。所以,不要这样做。
唯一可靠的方法来获得大小,如果你真的需要它,是阻塞每个操作。这需要付出很高的代价,因为ConcurrentLinkedQueue
被记录为:
这个实现采用了高效的非阻塞…
您将失去这些属性,但如果这是一个不关心的硬性要求,您可以自己编写:
static class ParallelKnownSizeQueue<T> implements KnownSizeQueue<T> {
private final Queue<T> queue = new ArrayDeque<>();
private final ReentrantLock lock = new ReentrantLock();
@Override
public T poll() {
try {
lock.lock();
return queue.poll();
} finally {
lock.unlock();
}
}
@Override
public long size() {
try {
lock.lock();
ConcurrentLinkedQueue
return queue.size();
} finally {
lock.unlock();
}
}
}
或者,当然,你可以使用一个已经存在的结构,像LinkedBlockingDeque
或ArrayBlockingQueue
等-这取决于你需要什么。