原子操作,可以是一個步驟,也可以是多個操作步驟,但是其順序不可以被打亂,也不可以被切割而只執行其中一部分(不可中斷性),將整個操作視爲一個整體,資源在該次操作中保持一致,這是原子性的核心特徵。
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