綜述
JDK從1.5開始提供了java.util.concurrent.atomic包。
通過包中的原子操作類能夠線程安全地更新一個變量。
包含4種類型的原子更新方式:基本類型、數組、引用、對象中字段更新。
atomic包中的原子操作類基本上內部都是使用Unsafe類實現的,原子更新的實質其實就是獲取內存偏移地址,對地址中的變量進行更新。
關於Unsafe類,可以參考我的這篇博文【Java並發】Java中的Unsafe類
1.原子更新基本類型類
atomic包內包含AtomicBoolean、AtomicInteger、AtomicLong這3個類,以下以AtomicInteger進行講解。
AtomicInteger是如何實現原子操作的?
是使用Unsafe類實現的,而Unsafe實現原子操作的原理是通過得到變量相對於對象示例的內存偏移地址,更新內存地址內的變量值。
下面是摘錄的AtomicInteger的部分源碼。
/** * Atomically increments by one the current value. * * @return the previous value */ public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } /** * Atomically decrements by one the current value. * * @return the previous value */ public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1); } /** * Atomically adds the given value to the current value. * * @param delta the value to add * @return the previous value */ public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta); } /** * Atomically increments by one the current value. * * @return the updated value */ public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } /** * Atomically decrements by one the current value. * * @return the updated value */ public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } /** * Atomically adds the given value to the current value. * * @param delta the value to add * @return the updated value */ public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; }
2.原子更新數組
atomic包內包含AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray這3個類,以下以AtomicIntegerArray進行講解。
AtomicIntegerArray是如何實現原子操作的?
是使用Unsafe類實現的,而Unsafe實現原子操作的原理是通過得到變量相對於數組的內存偏移地址,更新內存地址內的變量值。
下面是摘錄的AtomicIntegerArray的部分源碼。
/** * Atomically increments by one the element at index {@code i}. * * @param i the index * @return the previous value */ public final int getAndIncrement(int i) { return getAndAdd(i, 1); } /** * Atomically decrements by one the element at index {@code i}. * * @param i the index * @return the previous value */ public final int getAndDecrement(int i) { return getAndAdd(i, -1); } /** * Atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the previous value */ public final int getAndAdd(int i, int delta) { return unsafe.getAndAddInt(array, checkedByteOffset(i), delta); } /** * Atomically increments by one the element at index {@code i}. * * @param i the index * @return the updated value */ public final int incrementAndGet(int i) { return getAndAdd(i, 1) + 1; } /** * Atomically decrements by one the element at index {@code i}. * * @param i the index * @return the updated value */ public final int decrementAndGet(int i) { return getAndAdd(i, -1) - 1; } /** * Atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the updated value */ public final int addAndGet(int i, int delta) { return getAndAdd(i, delta) + delta; }
3.原子更新引用
使用AtomicInteger只能原子更新一個變量,如果要原子更新多個變量,就需要將多個變量封裝起來,原子更新對象引用。
atomic包內包含AtomicReference、AtomicReferenceFieldUpdater、AtomicUpdater這3個類,以下以AtomicIntegerArray進行講解。
下面是摘錄的AtomicReference的部分源碼。
/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(V expect, V update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ @SuppressWarnings("unchecked") public final V getAndSet(V newValue) { return (V)unsafe.getAndSetObject(this, valueOffset, newValue); }
4.原子更新字段類
用於更新類里的某個字段。
atomic包內包含AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference這3個類。
AtomicStampedReference 將整數值與引用關聯起來,可以用於原子地更新數據和數據的版本號,可以解決CAS的ABA問題。