18

我需要long具有以下要求/事实的类型计数器:

  • 递增计数器应该花费尽可能少的时间。
  • 计数器只会被一个线程写入。
  • 从计数器读取将在另一个线程中完成。
  • 计数器会定期递增(每秒最多几千次),但每五秒只会读取一次。
  • 精确的准确性不是必需的,只需粗略了解计数器的大小就足够了。
  • 计数器永远不会被清零,递减。

基于这些要求,您将如何选择实施您的计数器?作为一个简单的long,作为一个volatile long或使用一个AtomicLong?为什么?

目前我有一个volatile long但想知道另一种方法是否会更好。我也通过做++counter而不是增加我的长期counter++。因为没有完成任务,这真的更有效吗(正如我在其他地方被引导相信的那样)?

4

5 回答 5

12

鉴于这些要求,我认为volatilelong 应该足够了。非 long 的计数器不会不正确volatile,但在这种情况下,读者可能正在阅读陈旧的信息。

一个问题是,如果没有声明,JVM 规范并不要求long对 a的读取和写入必须是原子的。这意味着如果读取线程在写入线程已更新值的一部分而不是另一部分时读取该值,则读取线程可能会获得几乎虚构的值。volatile

++countercounter++之间的区别可能无关紧要,因为 JVM 将意识到不再使用表达式的值,并且在这种情况下两者是等价的。

于 2010-03-15T15:09:52.120 回答
5

在 Java 8 中,使用 LongAdder,它甚至比线程争用高的 AtomicLong 更好。

LongAdder JavaDoc:

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

于 2015-08-04T07:19:03.113 回答
0

您的程序的正常运行时间要求是什么?您可以使用非易失性 int 和 racy-reads 吗?

于 2010-03-15T15:32:18.420 回答
0

10^4 增量/秒是每 100 微秒 1。效率不是问题,但原子性可能是问题。您可能有 2 个副本,当读取时,如果它们不相等,请再次读取。

于 2010-03-15T17:26:48.333 回答
0

本文讨论了实现计数器的可能方法我认为这个实现应该适合你

class LessNaiveVolatieIdGenerator {
private static volatile long id = 0;
public static long nextId() {
    long nextId = (id = id + 1); // or nextId = id++;
    return nextId;
}

}

于 2011-12-01T01:05:55.313 回答