max 的线程安全实现

我需要为Web服务器实现全局对象收集统计信息。我有单例,它有方法,随后调用。这显然是线程安全的。我有这个方法来更新整个统计信息的最大值:StatisticsaddSample(long sample)updateMax

AtomicLong max;

private void updateMax(long sample) {
    while (true) {
        long curMax = max.get();
        if (curMax < sample) {
            boolean result = max.compareAndSet(curMax, sample);
            if (result) break;
        } else {
            break;
        }
    }
}

此实现是否正确?我正在使用java.util.concurrent,因为我相信它会比简单更快。有没有其他/更好的方法来实现这一点?synchronized


答案 1

从Java 8开始,LongAccumulator已经推出。建议作为

当多个线程更新用于收集统计信息等目的的公共值(而不是用于细粒度同步控制)时,此类通常比 AtomicLong 更可取。在低更新争用下,这两个类具有相似的特征。但在高争用下,此类的预期吞吐量明显更高,但代价是空间消耗较高。

您可以按如下方式使用它:

LongAccumulator maxId = new LongAccumulator(Long::max, 0); //replace 0 with desired initial value
maxId.accumulate(newValue); //from each thread

答案 2

我认为这是正确的,但为了清晰起见,我可能会重写一下,并一定要添加注释:

private void updateMax(long sample) {
    while (true) {
        long curMax = max.get();
        if (curMax >= sample) {
            // Current max is higher, so whatever other threads are
            // doing, our current sample can't change max.
            break;
        }

        // Try updating the max value, but only if it's equal to the
        // one we've just seen. We don't want to overwrite a potentially
        // higher value which has been set since our "get" call.
        boolean setSuccessful = max.compareAndSet(curMax, sample);

        if (setSuccessful) {
            // We managed to update the max value; no other threads
            // got in there first. We're definitely done.
            break;
        }

        // Another thread updated the max value between our get and
        // compareAndSet calls. Our sample can still be higher than the
        // new value though - go round and try again.
    }
}

编辑:通常我至少会先尝试同步版本,并且只有在我发现它引起问题时才选择这种无锁代码。


推荐