ConcurrentLinkedQueue的替代方案,我需要使用LinkedList与锁吗?



我目前正在使用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();
}
}
}

或者,当然,你可以使用一个已经存在的结构,像LinkedBlockingDequeArrayBlockingQueue等-这取决于你需要什么。

最新更新