【问题标题】:Alternative to ConcurrentLinkedQueue, do I need to use LinkedList with locks?ConcurrentLinkedQueue 的替代方案,我是否需要使用带锁的 LinkedList?
【发布时间】:2021-01-17 13:51:16
【问题描述】:

我目前正在使用 ConcurrentLinkedQueue,这样我就可以使用自然顺序 FIFO 并在线程安全应用程序中使用它。我需要每分钟记录一次队列的大小,并且鉴于此集合不保证大小并且计算大小的成本为 O(N),是否有任何替代的有界非阻塞并发队列可以在获取时使用size 不会是一个昂贵的操作,同时添加/删除操作也不昂贵?

如果没有集合,是否需要使用带锁的LinkedList?

【问题讨论】:

  • 给你这个要求的人应该阅读ConcurrentLinkedQueue的java文档。如果他/她说(或强迫您)使用带锁的Queue,请告诉他/她 高效非阻塞 特性(如文档ConcurrentLinkedQueue 说)将丢失。根本没有办法在不阻塞的情况下获得准确的当前大小。甚至维护一个单独的 LongAdderAtomicInteger 也无济于事。
  • 与查询之间的分钟(60,000,000,000 纳秒)相比,一个“正确”数字的价值是多少?同样,为什么要牺牲主操作的性能来换取每分钟只执行一次的操作的性能?

标签: java collections java-8


【解决方案1】:

如果您真的(真的)需要记录您当前正在处理的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 等 - 取决于您的需要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多