java - 为什么 AtomicInteger 和类似类的 getAndSet() 中存在循环?

标签 java concurrency

在这段代码中使用循环的目的是什么

public final int getAndSet(int newValue) {
    for (;;) {
        int current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

最佳答案

有一种观点认为你应该use locks as frugally as you can . IE。如果可以避免,切勿使用锁,如果必须使用,请锁定最短时间。这背后的原因是,有时首先获取锁定的成本相当高,以及一个线程等待而另一个线程持有它所需资源的锁定的成本。

有一个 very long time , cpu 指令称为 Compare and Set (或 CAS 简称) 旨在帮助解决这个问题:

if (value == providedValue) {
  value = newValue;
  return true;
} else {
  return false;
}

这些指令可以在机器代码级别执行,并且比创建锁要快得多。

想象一下,您想使用这些指令之一将 1 添加到一个数字上,这种方式在高并行负载下始终能正常工作。显然,您可以将其编码为:

int old = value;
if ( compareAndSet(old, old+1) ) {
  // It worked!
} else {
  // Some other thread incremented it before I got there.
}

但是如果 CAS 失败了怎么办?你猜对了 - 再试一次!

boolean succeeded = false;
do {
  int old = value;
  if ( compareAndSet(old, old+1) ) {
    // It worked!
    succeeded = true;
  } else {
    // Some other thread incremented it before I got there. Just try again.
  }
} while (!succeeded);

你会看到你观察到的模式。

使用这个和类似的习惯用法,可以实现许多功能,甚至是一些非常复杂的数据结构,完全不使用锁(通常称为无锁)。例如,hereRing Buffer 的无锁实现.

关于java - 为什么 AtomicInteger 和类似类的 getAndSet() 中存在循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30077080/

相关文章:

java - 如何在类定义中的泛型类型中捕获子类型?

python - 1 个带有 Gunicorn 的 Web Worker 是否总是意味着只有 1 个进程?

java - 同步惰性初始化时两次检查是否为空的原因是什么?

objective-c - 具有回调方法的 IOS Grand Central Dispatch

java - 安卓 Java : What happens in an AsyncTask with more than one task being operated?

java - 使用notify将线程从其状态唤醒

尝试在 jade 中打印容器 id 时出现 java.lang.ClassCastException

java - 简单的 Java 正则表达式不起作用

java - 选择排序中交换是如何工作的?

java - MPAndroidChart:为 Y 轴提供一些偏移量