我需要一个long
类型的计数器,其中包含以下要求/事实:
根据这些要求,您将如何选择实施计数器?简单long
,volatile long
或使用AtomicLong
?为什么呢?
目前我有一个volatile long
但是想知道另一种方法是否会更好。我也是通过++counter
而不是counter++
来增加我的长期。这真的更有效率(因为我已被引导相信其他地方),因为没有完成任务吗?
答案 0 :(得分:11)
鉴于这些要求,我认为 volatile
长就足够了。对于非volatile
长的计数器,计数器不会出错,但在这种情况下,读者可能会阅读过时的信息。
如果long
没有声明volatile
,则++counter
对counter++
的读写是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;
}
}