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

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

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

目前我有一个 volatile long 但是想知道另一种方法是否会更好。我也通过这样做很长时间 ++counter 而不是 counter++. 。这是否真的更有效(因为我已经被其他地方相信),因为没有完成任务?

有帮助吗?

解决方案

鉴于这些要求,我 思考volatile 长期应该足够。柜台不会不正确volatile 很长,但是读者可能正在阅读这种情况下的陈旧信息。

一个问题是阅读并写入 long不是 必需的 是原子, ,由 JVM规范 如果没有声明 volatile. 。这意味着,如果读取线程读取值,而写入线程已更新了值的一部分,而另一个则不能,则可以获得读取线程的虚拟值。

和...之间的不同 ++countercounter++大概 无关紧要的,因为JVM将意识到表达式不再使用,在这种情况下两者是等效的。

其他提示

在Java 8中,使用LongAdder,它比线程争论高的原子能更好。

Longadder Javadoc:

当多个线程更新用于诸如收集统计的目的,而不是用于细粒度的同步控制之类的通用总和时,通常比原子量更可取。在低更新的争论下,这两个类具有相似的特征。但是,在高度争论下,该类别的预期吞吐量明显更高,而牺牲了更高的空间消耗。

您的程序的正常运行时间是什么?您可以使用无私的INT和Racy-Reads做吗?

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

这个 文章 讨论实施计数器的可能方法,我认为此实施应该对您有用

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

}

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top