AtomicInteger 的实际用途

新手上路,请多包涵

我有点理解 AtomicInteger 和其他 Atomic 变量允许并发访问。在什么情况下通常使用此类?

原文由 James P. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 751
2 个回答

AtomicInteger 有两个主要用途:

  • 作为原子计数器( incrementAndGet() 等),可以同时被多个线程使用

  • 作为支持 比较和交换 指令 ( compareAndSet() ) 以实现非阻塞算法的原语。

这是来自 Brian Göetz 的 Java Concurrency In Practice 的非阻塞随机数生成器示例:

   public class AtomicPseudoRandom extends PseudoRandom {
      private AtomicInteger seed;
      AtomicPseudoRandom(int seed) {
          this.seed = new AtomicInteger(seed);
      }

      public int nextInt(int n) {
          while (true) {
              int s = seed.get();
              int nextSeed = calculateNext(s);
              if (seed.compareAndSet(s, nextSeed)) {
                  int remainder = s % n;
                  return remainder > 0 ? remainder : remainder + n;
              }
          }
      }
      ...
  }

如您所见,它的工作方式基本上与 incrementAndGet() 几乎相同,但执行任意计算 ( calculateNext() ) 而不是递增(并在返回前处理结果)。

原文由 axtavt 发布,翻译遵循 CC BY-SA 2.5 许可协议

我能想到的最简单的例子就是使递增成为一个原子操作。

使用标准整数:

 private volatile int counter;

public int getNextUniqueIndex() {
    return counter++; // Not atomic, multiple threads could get the same result
}

使用原子整数:

 private AtomicInteger counter;

public int getNextUniqueIndex() {
    return counter.getAndIncrement();
}

后者是执行简单突变效果(特别是计数或唯一索引)的一种非常简单的方法,而无需求助于同步所有访问。

可以使用更复杂的无同步逻辑 compareAndSet() 作为一种乐观锁定 - 获取当前值,基于此计算结果,设置此结果 iff 值仍然是用于进行计算的输入,否则重新开始 - 但计数示例非常有用,我会经常使用 AtomicIntegers 进行计数和 VM-wide unique generators 如果有任何涉及多个线程的提示,因为它们非常简单与我一起工作我几乎认为使用普通 ints 是过早的优化。

虽然您几乎总是可以通过 ints 和适当的 synchronized 声明实现相同的同步保证,但 AtomicInteger 的美妙之处在于内置于实际线程安全中对象本身,而不是您需要担心碰巧访问 int 值的每个方法可能的交错和持有的监视器。调用 getAndIncrement() 时意外违反线程安全比返回 i++ 并记住(或不)事先获取正确的监视器集要难得多。

原文由 Andrzej Doyle 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题