
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
昆明IT培训的老师这一期给大家分享理解什么是原子性操作,意思是不能再拆分的操作,例如改写一个值,读取一个值都属于原子性操作。
那么CAS是两个操作,先比较旧值,比较通过后再进行改写,这种连合操作合并成一个指令交给CPU,由CPU操作来确保这是一个原子性操作。
多线程同时改写同一个值时,每个线程携带自己的旧值和新值交给CPU改写,CPU的运行是按逐条指令运行,如果发现旧值不符合,线程就会收到改写失败回应。
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
因此AtomicInteger#incrementAndGet()方法里,会循环尝试使用compareAndSet(...)方法,直到成功为止。
相关的原子类所在包:java.util.concurrent.atomic
Atomic + Boolean/Integer/Long/Reference
操作一个对应的类型对象
Atomic + Integer/Long/Reference + Array
操作一个对应类型的数组
Atomic + Integer/Long/Reference + FieldUpdater
操作一个对应类型的Field对象,类似反射方式改写对象字段
原子类会出现ABA时带来的隐患,文中举了一个例子,一个单向的链表实现了堆栈操作,使用一个原子变量作为链头指针,现在链头是A,A的next是B。有两个线程分别是T1和T2,他们并发的操作如下:
T1:AB => B
T2:AB => B =>空=> D => CD => ACD
由于线程T1只认链头是不是A,如果是A,就会将链头指向B,因此可能会出现直接把ACD变成B,这就是ABA并发的隐患。
AtomicMarkableReference
操作一个对象类型和boolean类型的二元组
AtomicStampedReference
操作一个对象类型和int类型的二元组
虽然例子中链头指针是一个原子变量,会出现ABA的情况,但如果再增加一个原子变量,这个原子变量确保不会出现ABA的情况,两个原子变量作为二元组进行原子性操作,即使用AtomicStampedReference就可以有效解决这个ABA的隐患了。