//以原子的方式将实例中的原值加1,返回的是自增前的旧值;
public final int getAndIncrement() {
return (this, valueOffset, 1);
}
//getAndSet(int newValue):将实例中的值更新为新值,并返回旧值; 、
public final boolean getAndSet(boolean newValue) {
boolean prev;
do {
prev = get();
} while (!compareAndSet(prev, newValue));
return prev;
}
//incrementAndGet() :以原子的方式将实例中的原值进行加1操作,并返回最终相加后的结果;
public final int incrementAndGet() {
return (this, valueOffset, 1) + 1;
}
//addAndGet(int delta) :以原子方式将输入的数值与实例中原本的值相加,并返回最后的结 果;
public final int addAndGet(int delta) {
return (this, valueOffset, delta) + delta;
}
测试
public class AtomicIntegerTest {
static AtomicInteger sum = new AtomicInteger(0);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() ->{
for (int j = 0; j < 10000; j++) {
// 原子自增 CAS
();
}
}).start();
}
try {
(3000);
} catch (InterruptedException e) {
();
}
(());
}
}
incrementAndGet()方法通过CAS自增实现,如果CAS失败,自旋直到成功+1。
public final int incrementAndGet() {
return (this, valueOffset, 1) + 1;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = (var1, var2);
} while(!(var1, var2, var5, var5 + var4));
return var5;
}
CAS缺陷
CAS 虽然高效地解决了原子操作,但是还是存在一些缺陷的,主要表现在三个方面:
- 自旋 CAS 长时间地不成功,则会给 CPU 带来非常大的开销
- 只能保证一个共享变量原子操作
- ABA 问题
ABA问题代码演示
AtomicInteger atomicInteger = new AtomicInteger(1);
new Thread(()->{
int value = ();
("Thread1 read value: " + value);
// 阻塞1s
(1000000000L);
// Thread1通过CAS修改value值为3
if ((value, 3)) {
("Thread1 update from " + value + " to 3");
} else {
("Thread1 update fail!");
}
},"Thread1").start();
new Thread(()->{
int value = ();
("Thread2 read value: " + value);
// Thread2通过CAS修改value值为2
if ((value, 2)) {
("Thread2 update from " + value + " to 2");
// do something
value = ();
("Thread2 read value: " + value);
// Thread2通过CAS修改value值为1
if ((value, 1)) {
("Thread2 update from " + value + " to 1");
}
}
},"Thread2").start();
//[Thread1] DEBUG - Thread1 read value: 1
//[Thread2] DEBUG - Thread2 read value: 1
//[Thread2] DEBUG - Thread2 update from 1 to 2
//[Thread2] DEBUG - Thread2 read value: 2
//[Thread2] DEBUG - Thread2 update from 2 to 1
//[Thread1] DEBUG - Thread1 update from 1 to 3