AtomicInteger 中的 "Compare And Set" 如何工作
How does "Compare And Set" in AtomicInteger works
AtomicInteger
使用两个概念:CAS 和 volatile
变量。
使用 volatile
变量确保当前值对所有线程可见并且不会被缓存。
但是我对下面解释的 CAS(比较和设置)概念感到困惑:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
我的问题是什么if(compareAndSet(current, next)
returns false
?值不会更新吗?
在这种情况下,当线程执行以下情况时会发生什么:
private AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
for (;;)
是一个无限循环,所以它只会重试。
原子对象利用 Compare and Swap 机制使它们成为原子对象 - 即可以保证值 是 指定的 和现在 为新值。
您发布的代码不断尝试将当前值设置为比以前多 1。请记住,另一个线程也可能已经执行了 get
并且正在尝试设置它。如果两个线程相互竞争以更改值,则其中一个增量可能会失败。
考虑以下场景:
- 线程 1 调用
get
并获取值 1
。
- 线程 1 将
next
计算为 2
。
- 线程 2 调用
get
并获取值 1
。
- 线程 2 将
next
计算为 2
。
- 两个线程都尝试写入值。
现在由于原子性 - 只有一个线程会成功,另一个将从 compareAndSet
接收 false
并再次运行。
如果不使用此机制,则很可能两个线程都递增该值,导致实际上只进行一次递增。
令人困惑的无限循环for(;;)
只有在多个线程同时写入变量时才会真正循环。在非常重的负载下,它可能会循环几次,但应该会很快完成。
AtomicInteger
使用两个概念:CAS 和 volatile
变量。
使用 volatile
变量确保当前值对所有线程可见并且不会被缓存。
但是我对下面解释的 CAS(比较和设置)概念感到困惑:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
我的问题是什么if(compareAndSet(current, next)
returns false
?值不会更新吗?
在这种情况下,当线程执行以下情况时会发生什么:
private AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
for (;;)
是一个无限循环,所以它只会重试。
原子对象利用 Compare and Swap 机制使它们成为原子对象 - 即可以保证值 是 指定的 和现在 为新值。
您发布的代码不断尝试将当前值设置为比以前多 1。请记住,另一个线程也可能已经执行了 get
并且正在尝试设置它。如果两个线程相互竞争以更改值,则其中一个增量可能会失败。
考虑以下场景:
- 线程 1 调用
get
并获取值1
。 - 线程 1 将
next
计算为2
。 - 线程 2 调用
get
并获取值1
。 - 线程 2 将
next
计算为2
。 - 两个线程都尝试写入值。
现在由于原子性 - 只有一个线程会成功,另一个将从 compareAndSet
接收 false
并再次运行。
如果不使用此机制,则很可能两个线程都递增该值,导致实际上只进行一次递增。
令人困惑的无限循环for(;;)
只有在多个线程同时写入变量时才会真正循环。在非常重的负载下,它可能会循环几次,但应该会很快完成。