计数器的长原始或原子长?

时间:2010-03-15 14:57:53

标签: java performance java.util.concurrent

我需要一个long类型的计数器,其中包含以下要求/事实:

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

根据这些要求,您将如何选择实施计数器?简单longvolatile long或使用AtomicLong?为什么呢?

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

5 个答案:

答案 0 :(得分:11)

鉴于这些要求,我认为 volatile长就足够了。对于非volatile长的计数器,计数器不会出错,但在这种情况下,读者可能会阅读过时的信息。

如果long没有声明volatile,则++countercounter++的读写是not required to be atomic。这意味着如果读取线程在写入线程更新了值的一部分而不是另一部分时读取了值,则读取线程可以获得相当大的虚拟值。

{{1}}和{{1}}之间的差异可能无关紧要,因为JVM会意识到表达式的值不再使用,而且两者在这种情况。

答案 1 :(得分:4)

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

LongAdder JavaDoc:

  

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

答案 2 :(得分:0)

您的计划的正常运行时间要求是什么?你能用un-volatile int和racy-reads来做吗?

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

}