【问题标题】:size of ConcurrentLinkedQueueConcurrentLinkedQueue 的大小
【发布时间】:2011-02-15 01:58:54
【问题描述】:

阅读Java's ConcurrentLinkedQueue Docs,不知为何实现无法存储大小:

请注意,与大多数集合不同,size 方法不是恒定时间操作。由于这些队列的异步特性,确定当前元素的数量需要遍历元素。

the source 的“异步性质”在哪里? 我只看到一个 while 循环来重试排队,直到 AtomicReferences 与预期值/引用匹配。为什么在成功向队列提供值后不能增加size:AtomicInteger

非常感谢。

【问题讨论】:

    标签: java size queue concurrency


    【解决方案1】:

    假设您有两个线程,一个添加新项目,另一个删除一个项目。开始时队列中没有项目。

    假设第一个线程添加项目,紧接着另一个线程删除项目并减小大小,此时您的大小为 -1,然后第一个线程将大小增加到 0。

    一个稍微做作的例子,但您需要使整个操作原子化,以确保没有其他线程可以访问 -1 的大小。

    【讨论】:

    • 好的,我理解递减/递增的执行顺序是不确定的。但是计数器获得近似的队列大小就足够了,不是吗?
    • Finbarr,如果队列管理自己的大小,它肯定会在其(同步)添加/删除方法中这样做,是吗?那么大小什么时候会是-1?
    • @CPerkins:您应该在回复之前阅读源代码。 ConcurrentLinkedQueue 是“无需等待的”。它是线程安全的,没有同步方法。
    • @CPerkins:Impl 通过使用 atomic-references 和 not 使用 synchronized 是无等待的。所以你必须明确地在计数器上同步,因为增量/减量本身是原子的,但提供/轮询的整个操作不是原子的,所以 Finbarr 应该是正确的。
    • @hotzen +1 回复与我输入的几乎完全相同。
    【解决方案2】:

    ConcurrentLinkedQueue 的一个重要性能优势来自这样一个事实,即您在更新头部时不必担心尾部,反之亦然,对吗?

    这基本上意味着 2 个线程可以同时轮询/提供而不会干扰(如果队列大小不为 0,即)。

    如果您有柜台,情况就不是这样了。即使它是具有良好并发性的AtomicInteger,您仍然会增加 CAS 操作失败的可能性,因为现在您有了这个“热点”,每次进行轮询/报价时都会更新。

    不完全确定作者在说“异步性质”时是否是这个意思,但我认为这是他们没有像你建议的那样计数器的最大原因。

    【讨论】:

    • 有道理,谢谢。但我真的很想知道它们对“异步性质”的含义......
    • @hotzen:为什么不问问作者呢?我相信他们会给你一个答案。只需谷歌“并发兴趣”并在他们的邮件列表上发布..
    【解决方案3】:

    为什么不能增加 size:AtomicInteger 成功后 为队列提供价值?

    可能是因为该提议/递减不能以原子方式完成而不会对方法的并发性产生不利影响。

    【讨论】:

    • 因为计数器将成为报价和投票的同步点?这就说得通了。但是,如果需要,我没有看到任何会阻碍此类计数器的“异步”行为。
    猜你喜欢
    • 2010-11-28
    • 1970-01-01
    • 2010-10-11
    • 2013-09-12
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多