AtomicInteger 的实际用途

2022-08-31 05:26:28

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


答案 1

有两个主要用途: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()


答案 2

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

使用标准 ints:

private volatile int counter;

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

使用 AtomicInteger:

private AtomicInteger counter;

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

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

更复杂的无同步逻辑可以用作一种乐观锁定 - 获取当前值,基于此计算结果,设置此结果iff值仍然是用于执行计算的输入,否则重新开始 - 但是计数示例非常有用,如果有任何涉及多个线程的提示,我将经常用于计数和VM范围的唯一生成器, 因为它们非常容易使用,我几乎认为使用普通.compareAndSet()AtomicIntegersints

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


推荐