AtomicInteger:保持非负数

2022-09-03 05:36:39

有没有办法用 ?要阐明所需的行为,请执行以下操作:AtomicInteger

  • 如果当前值大于零,则递减
  • 如果当前值等于零,则不执行任何操作
  • (不处理负电流值)

答案 1

在 Java 8 中,是的

atomicInteger.updateAndGet(i -> i > 0 ? i - 1 : i); 

在Java 8之前,没有


答案 2

我想你可以做一些像Java 8之前这样的事情:

int val = atomicInt.get();
boolean success = false;
while(val > 0 && !success) {
    success = atomicInt.compareAndSet(val, val - 1);
    if(!success) {
        // Try again if the value is still > 0
        val = atomicInt.get();
    }
}
// Check 'success' to see if it worked

不是最优雅的代码,但我认为它确实有效。


非正式的正确性证明(由@Stephen C)

在没有其他线程修改的情况下,在第一次调用时将设置为 。所以代码将等效于AtomicIntegersuccesstruecompareAndSet

int val = atomicInt.get();
if (val > 0) {
    atomicInt.compareAndSet(val, val - 1);
}

这显然是正确的。

如果某些其他线程修改 了 和 之间的 ,则后一个调用将失败,因为当前值不再等于 。因此,接下来发生的事情是我们再次调用以获取更新的值...并重复。我们不断重复,直到我们成功了OR,或者电流小于零或更小。AtomicIntegergetcompareAndSetvalatomicInt.get()compareAndSetval

净效应是,此线程要么递减一次,要么因为看到值为零而放弃。AtomicInteger

请注意以下注意事项:

  1. 重试循环可能会导致另一个线程“超车”并在线程之前使其递减。(另一种说法是说算法不“公平”。
  2. 如果您立即观察到此序列之后的值,您可能会观察到其值已更改...的 HA。AtomicInteger
  3. 从理论上讲,代码可以无限期地循环。但这需要其他线程不断更新 .AtomicInteger

但是,这些警告都没有违反(假设的)要求。


推荐