原子整数增量和获取原子性



AtomicInteger.incrementAndGet() 根据文档是原子的。但是,在下面的源代码中,如果另一个线程在"返回下一个"之前交错怎么办?那么"下一个"会不正确吗?

public final long incrementAndGet() {
    for (;;) {
        long current = get();
        long next = current + 1;
        if (compareAndSet(current, next))
          return next;
    }
}

如果另一个线程交错,那么它也将成功地将一个添加到值中。

原子性保证您的增量发生,如果两个线程尝试增量,那么最终两个线程将成功(并递增两个)。它不保证任何未来价值。

在您的方案中,它看起来像以下代码:

public final long incrementAndGet() {
    for (;;) {
        long current = get();
        long next = current + 1;
        if (compareAndSet(current, next)) {
            // Other thread.
            for (;;) {
                long current2 = get();
                long next2 = current2 + 1;
                if (compareAndSet(current2, next2)) {
                    return next2;
                }
            }
            return next;
        }
    }
}

即每个线程都获得自己的递增值。

该值随每次调用正确递增,因此它唯一可能影响的是返回值。

该函数的语义是它不返回整数的当前值,而是返回调用incrementAndGet()增加整数的值(更新的值)。

我举个例子:

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

现在,如果您调用getNextUniqueIndex()它将始终返回唯一值,无论调用线程或线程交错。这是因为从incrementAndGet()的实现中返回的next值是指此incrementAndGet()调用更新的值。

如果在compareAndSet之后,那么是的,增量AndGet可能会向其他线程提供更高的值。然而,返回后也是如此。该值将增加两个(正确),并且两个线程将收到不同的值。

这形成了"正确"的语义。对于并行线程,没有完美的时间同步性。

compareAndSet 方法保证更新的原子性,但不能保证返回的值是"最新"。incrementAndGet仅保证 1) 该值以原子方式递增,2) 您获得该递增的结果。在成功增量之前(或之后)发生的事情与当前Thread无关。

什么是

"正确"?

下一个值不是 AtomicInteger 的当前值,而是递增"当前"值产生的值。

假设以下模拟(以这种方式,"线程 2"在"返回下一个"之前交错"线程 1")

i = 10
Thread 1
calling 'j = incrementAndGet(i)'
computing incrementAndGet(i) by Thread 1
now i = 11
Thread 2
calling 'm = incrementAndGet(i)'
computing incrementAndGet(i) by Thread 2
now i = 12 
Thread 1
now j = 11 
Thread 2
now m = 12 
Thread 3
calling 'n = incrementAndGet(i)'
// Hey! It should be only with Thread 1 and 2!
now i = 13 and n = 13

事实上,增量和获取是原子的。为什么?因为线程 1 在我 10 岁时调用增量和获取并得到 11。线程 2 在我 11 岁时称为 incrementAndGet,得到 12。我是否会被改变并不重要。在增量和获取之后,调用方在增量后获得结果值。

增量AndGet正在使用compareAndSet,它正在使用unsafe.compareAndSwapInt。此方法以原子方式将 Java 变量更新为给定整数(如果它当前保存预期的整数)。

因此,当两个线程尝试递增该值时,JVM将以原子方式比较现有值,如果它相同,则增量将成功,否则将不会成功。

相关内容

  • 没有找到相关文章

最新更新