【问题标题】:Using LongAdder to calculate a max value for a statistical counter?使用 LongAdder 计算统计计数器的最大值?
【发布时间】:2016-04-01 01:42:20
【问题描述】:

我们使用 AtomicLongs 收集一些统计数据。一些用户看到了这些问题,并建议改用 LongAdder。但是,我认为无法像我们目前使用 Atomic 一样计算最大值:

AtomicLong _current, _total, _max;
...

void add(long delta)
{
  long current = _current.addAndGet(delta);
  if (delta>0)
  {
    _total.addAndGet(delta);
    long max = _max.get();
    while (current > max)
    {
      if (_max.compareAndSet(max, current))
        break;
      max = _max.get();
    }
 }

所以我认为我们可以很容易地用LongAdder 替换_total,但是因为我们做了_current.addAndGet(delta),所以对于LongAdder 来说效果不佳,我们也不能对`_max' 值进行cas 操作.

有没有什么好的算法可以基于LongAdder 或类似的可扩展无锁结构来收集此类统计信息?

实际上,当我问到时,我们的统计数据通常会更新 6 到 10 个 AtomicLong。如果我们仍然看到争用,是否只获取一个锁并更新 6 到 10 个正常的 long 会更好吗?

【问题讨论】:

    标签: java concurrency statistics java-8 java.util.concurrent


    【解决方案1】:

    你不想要LongAdder,但在这里LongAccumulator:你想要new LongAccumulator(Math::max, Long.MIN_VALUE),它在这里做正确的事。 LongAdderLongAccumulator 的特例。

    【讨论】:

    • 啊,这将允许将 _max 转换为 LongAccumulator,但它对 _current 所需的 addAndGet 语义没有帮助。但是它仍然允许将 3 个 AtomicLong 替换为 1 个 AtomicLong、1 个 LongAdder 和 1 个 LongAccumulator
    • @gregw:您是否可以进一步简化它,取决于您在发布的方法之外实际使用这些值做什么。从您展示的那个单一方法中,所有三个都将始终包含相同的值,因此,可以用一个 LongAdder 替换...
    • @Holger 这三个值并不总是相同,因为可以传入负增量。
    • @gregw:我明白了。这让我想知道实际的用例。如果此时假设高争用,实际结果取决于不可预测的线程调度,因为累积 -1, +1, -1, +1 将产生与累积 +1, +1, -1, -1 不同的最大值,即使只有纳秒的差异(我们实际上可能会遇到同时所有四个值,但AtomicLong 强制执行任意串行更新顺序)...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 2015-09-09
    • 2015-10-29
    • 2018-07-31
    • 1970-01-01
    相关资源
    最近更新 更多