将 AtomicLong 递减一定增量的正确方法

Correct way to decrement an AtomicLong by a certain delta

给定一个 AtomicLong 对象,将值递减 delta 的正确方法是什么?

选项 1

AtomicLong count = new AtomicLong(0L);

public void decrementCount(long decrementBy) {
       count.getAndUpdate(l->count.get() - decrementBy);
}

选项 2

AtomicLong count = new AtomicLong(0L);

public void decrementCount(long decrementBy) {
       count.getAndAdd(-decrementBy);
}

虽然两者都给出了期望的结果,但我想了解在什么情况下它们不会代表期望的行为,即自动递减 long 值? (例如,第二种方法的一个缺点可能是负号导致一些位溢出,但我不确定这是不是真的)

你的第二种方法是正确的,如getAndAdd):

Atomically adds the given value to the current value

AtomicLong count = new AtomicLong(0L);
count.getAndAdd(-decrementBy);

您的第一种方法略有偏差,因为它在 "The function should be side-effect-free" 时使用 count.get()LongUnaryOperator,即理想情况下仅使用作为参数给出的长值。虽然读取原子值可能不能严格算作副作用,但没有必要也不必要地使更新成为非原子的。

count.getAndUpdate(l->count.get() - decrementBy);

这不是自动运行的。 getAndUpdate 大致是这样工作的:

long getAndUpdate(LongUnaryOperator op) {
  long current;
  long newValue;
  do {
    current = this.get();
    newValue = op.apply(current);
  while (!compareAndSet(current, newValue));
  return current;
}

通过重新读取 lambda 内部的 count.get(),您正在读取 AtomicLong then 的值,这可能与值不同current 表示已通过,如果其他线程更新了中间的 AtomicLong;然后您将根据更新后的值进行更新,而不是 current.

使用您在 l 中传递的值:

count.getAndUpdate(l->l - decrementBy);

但是 getAndAdd(-decrementBy) 更容易。

我认为这个 class 的所有方法都准备好了:

The AtomicLong class provides you with a long variable which can be read and written atomically, and which also contains advanced atomic operations

取决于您希望在更新之前和之后使用的顺序,或者先更新然后阅读。你有递增和递减的 arpopiate 方法:

    addAndGet()
    getAndAdd()
    getAndIncrement()
    incrementAndGet()
    getAndDecrement()
    decrementAndGet()

然后是这样的:

AtomicLong atomicLong = new AtomicLong(22);

System.out.println(atomicLong.getAndAdd(-1));
System.out.println(atomicLong.addAndGet(-1));