AtomicLong运营

我需要执行以下操作:

// average, total, elapsed are Long's average = ( ( total * average ) + elapsed ) / (++total); 

但我想使用AtomicLong

这就是我正在尝试但如果它是正确的我不会得到:

  average.set( (( total.get() * average.get() ) + elapsed) / total.getAndIncrement() ); 

我怎么知道这是否正确?

据推测,您使用的是AtomicLong,因为这些数字是同时访问的。 由于您涉及两个数字并且您在同一语句中同时使用get和incrementAndGet,因此我认为AtomicLong不是正确的选择。

我发现AtomicXXX在很多情况下都非常有用。 但在这里,我认为你需要以艰难的方式去做。 使您的数字成为简单的“长”私有变量,创建一个保护对象,然后确保在您访问数字时同步保护对象。

我认为这是你可以确定这些操作真正primefaces化的唯一方法。

首先请注意,在某些平台上, AtomicLong是通过锁实现的,因此您可能会发现性能存在显着差异。

您似乎尝试一次更新两个变量。 虽然许多现代处理器都支持它,但Java库却没有。 带锁的版本是微不足道的,所以我会忽略它。 你可能还想计算得到的平均值,并保持一个运行总和和总数,但我暂时忽略它。

最直接的实现是将AtomicReference用于不可变值。 请注意,这将导致分配,因此可能具有很好的性能,尤其是在低争用情况下。

 final class Average { // Find a better name... private final long average; private final long total; public Average(long average, long total) { this.average = average this.total = total; } public long average() { return average; } public long total() { return total; } } ... private final AtomicReference averageRef = new AtomicReference<>(); private void elapsed(final long elapsed) { Average prev; Average next; do { prev = average.get(); next = new Average( ((prev.total() * prev.average()) + elapsed ) / (prev.total() + 1), prev.total() + 1 ); } while (!average.compareAndSet(prev, next)); } 

可能更好的解决方案是保持一个本地线程(最好不是ThreadLocal而是一个你给特定线程变异的实例)。 这可以非常快速地锁定和解锁,因为它将来自同一个线程。 不经常需要平均值的线程然后可以锁定和读取/读取来自所有线程的当前值。

 class Average { // Choose better name private long sum; private long total; public synchronized void elapsed(final long elapsed) { sum += elapsed; ++total; } public static long average(Iterable averages) { long sum = 0; long total = 0; for (Average average : averages) { synchronized (average) { sum += averages.sum; total += average.total; } } return total==0 ? 0 : (sum/total); } } 

(免责声明:未经检查或测试或编译。)

假设这些计算将由多个线程同时调用。 我最初没有将其付诸实施。

如果您想使用AtomicLong进行预增量计算,那么您应该执行以下操作:

 long value = total.getAndIncrement(); average.set((value * average.get()) + elapsed) / (value + 1)); 

仍然具有竞争条件,但是因为平均值可以由average.get()average.set()调用之间的其他人更新,这在更新中不会生效。

要完全确定,您需要(如他们的答案中提到的@ user1657364)锁定一个保护对象。

在你的作业中,总数和总++中的总数可能不同。 您需要同步整个操作。