Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 计数器是长原语还是原子长?_Java_Performance_Java.util.concurrent - Fatal编程技术网

Java 计数器是长原语还是原子长?

Java 计数器是长原语还是原子长?,java,performance,java.util.concurrent,Java,Performance,Java.util.concurrent,我需要一个long类型的计数器,具有以下要求/事实: 增加计数器所需的时间应尽可能少 计数器将仅由一个线程写入 从计数器读取数据将在另一个线程中完成 计数器将定期递增(高达每秒数千次),但每五秒钟只读取一次 精确的精度并不重要,只要大致了解一下计数器的大小就足够了 计数器永远不会被清除、递减 基于这些要求,您将如何选择实现计数器?作为简单的long,作为volatile long或使用AtomicLong?为什么? 目前,我有一个波动性很强的,但我想知道另一种方法是否会更好。我还通过执行++

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

  • 增加计数器所需的时间应尽可能少
  • 计数器将仅由一个线程写入
  • 从计数器读取数据将在另一个线程中完成
  • 计数器将定期递增(高达每秒数千次),但每五秒钟只读取一次
  • 精确的精度并不重要,只要大致了解一下计数器的大小就足够了
  • 计数器永远不会被清除、递减
基于这些要求,您将如何选择实现计数器?作为简单的
long
,作为
volatile long
或使用
AtomicLong
?为什么?


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

考虑到这些要求,我认为一个
volatile
长时间应该足够了。对于非volatilelong,计数器不会不正确,但在这种情况下,读取器可能正在读取过时的信息

一个问题是,如果未声明
为volatile
,则对
long
的读写是。这意味着,如果读线程在写线程更新了值的一部分而不是另一部分时读取该值,那么读线程可能会得到一个几乎是虚构的值


++counter
counter++
之间的差异可能无关紧要,因为JVM将意识到表达式的值不再使用,在这种情况下,这两个值是等效的。

您的程序的正常运行时间要求是什么?你能接受一个非易失性的int和racy读数吗?

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

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

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

}

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

LongAdder JavaDoc:

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


volatile应该可以,因为契约规定volatile变量的每次读取都是在前一次写入的锁释放之后进行的。如果您每秒只更新它几千次,并且使用的是非嵌入式处理器,那么差异就无关紧要了;如今,在大多数机器上,每秒都可以进行数百万次原子级更新。不过,我还是同意,
volatile
应该足够了。如果您想确定的话,您可以同时对两者进行编码,并检查它们匹配的频率(以及它们不匹配时的距离)。@Riduidel我们正在计算传入的数据包,我不在乎这个数字是12345678还是12345602稍微晚一点运行时间尽可能长-这是在服务器内部运行的。争用率不高。只有一个线程将向其写入。