AtomicInteger.incrementAndGet()是原子的。但是,在下面的源代码中,如果另一个线程在&#34之前交错怎么办?返回下一个"? "接着"那会不正确吗?
public final long incrementAndGet() {
for (;;) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
答案 0 :(得分:6)
如果另一个线程交错,那么它也会成功地向该值添加一个。
Atomicity保证你的增量发生,如果两个线程尝试增加,那么最终两个线程将成功(并且增加2)。它不保证任何未来价值。
在您的方案中,它看起来像以下代码:
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;
}
}
}
即。每个线程获得它自己递增的值。
答案 1 :(得分:3)
每次调用都会正确递增值,因此唯一可能影响的是返回值。
该函数的语义是它不返回整数的当前值,但调用incrementAndGet()
的值增加了整数(更新后的值) 。
让我举个例子:
public MyClass {
private AtomicInteger counter;
public int getNextUniqueIndex() {
return counter.getAndIncrement();
}
}
现在,如果你调用getNextUniqueIndex()
,它将始终返回一个唯一值,而不管调用线程或线程交错。这是因为从next
的实现返回的incrementAndGet()
的值是指此incrementAndGet()
调用更新的值。
答案 2 :(得分:2)
什么是"正确"?
下一个值不是AtomicInteger的当前值,而是通过递增"当前"得到的值。值。
让我们假设以下模拟(以这种方式,"线程2"交错"线程1"就在&#34之前;返回下一个")
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
确实,incrementAndGet是原子的。为什么?因为当我10岁时,线程1调用incrementAndGet并且得到11.当我11岁时,线程2调用incrementAndGet并且得到12.如果我将被更改并不重要。在incrementAndGet之后,调用者在增量后得到结果值。
答案 3 :(得分:2)
如果在compareAndSet
之后然后是,则incrementAndGet可能会向其他某个线程传递更高的值。但是,在返回后,它将保持。该值将增加2(正确),并且两个线程都将获得不同的值。
这形成了“正确”的语义。对于平行线程,没有完美的时间同步性。
答案 4 :(得分:2)
compareAndSet
方法保证更新的原子性,但不能保证返回的值是'latest'。 incrementAndGet
仅保证1)值以原子方式递增,2)得到该增量的结果。成功增量之前(或之后)发生的事情与当前Thread
无关。
答案 5 :(得分:1)
incrementAndGet正在使用compareAndSet,它正在使用unsafe.compareAndSwapInt。 此方法如果Java变量当前保持预期的整数,则将其原子更新为给定的整数。
因此,当两个线程尝试递增该值时,如果JVM相同则JVM将自动比较现有值,则增量将成功,否则它将不会成功。