原子操作,可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中一部分(不可中断性),将整个操作视为一个整体,资源在该次操作中保持一致,这是原子性的核心特征。
CAS机制
compare and swap,属于硬件同步原语,处理器提供了基本内存操作的原子性保证。
CAS操作,需要输入两个数值,一个旧值一个新值,在操作期间先比较下旧值有没有发生变化,如果没有发生变化,才交换成新值;如果发生了变化,则不交换。
使用Java中Unsafe类实现CAS机制:
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
public class UnsafeTest {
private volatile int index = 0;
// 类似直接操作内存
private static Unsafe unsafe;
// 属性内存偏移量
private static long indexOffset;
static {
try {
// 通过反射拿到对象
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
// 通过属性偏移量,定位内存中具体对象内具体属性的内存地址
indexOffset = unsafe.objectFieldOffset(UnsafeTest.class.getDeclaredField("index"));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
public void incr() {
int currentIndex;
int newIndex;
do {
currentIndex = unsafe.getIntVolatile(this, indexOffset);
newIndex = currentIndex + 1;
} while (!unsafe.compareAndSwapInt(this, indexOffset, currentIndex, newIndex));
// CAS 如果index值发生变化,操作失败,直到修改成功跳出循环
}
public int getIndex() {
return index;
}
public static void main(String[] args) throws InterruptedException {
UnsafeTest unsafeTest = new UnsafeTest();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 10000; j++) {
unsafeTest.incr();
}
}).start();
}
TimeUnit.SECONDS.sleep(2);
System.out.println(unsafeTest.getIndex());
}
}
当然在JDK中已经给我们提供了很多原子操作封装类,在java.util.concurrent.atomic这个包下,也就是平常说的JUC包下的atomic包;
原子类分四类
- 基本类型
- AtomicBoolean
- AtomicInteger
- AtomicLong
- 数组类型
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray
- 引用类型
- AtomicReference
- AtomicStampedReference
- AtomicMarkableReference
- 对象属性修改类型
- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicReferenceFieldUpdater