1
今天我們來(lái)聊聊java.util.concurrent.atomic
包下的原子類斯辰,所謂原子類就是具有原子/原子操作特征的類,在多個(gè)線程一起執(zhí)行的時(shí)候,一個(gè)操作一旦開(kāi)始吩坝,就不會(huì)被其它線程干擾。
Java8下原子類包括:
原子更新基本類型
- AtomicInteger 整型原子類
- AtomicLong 長(zhǎng)整型原子類
- AtomicBoolean 布爾型原子類
原子更新數(shù)組
- AtomicIntegerArray 整型數(shù)組原子類
- AtomicLongArray 長(zhǎng)整型數(shù)組原子類
- AtomicReferenceArray 引用類型數(shù)組原子類
原子更新引用
- AtomicReference 引用類型原子類
- AtomicReferenceFieldUpdater 原子更新引用類型里的字段
- AtomicMarkableReference 原子更新帶有標(biāo)記位的引用類型
原子更新字段
- AtomicIntegerFieldUpdater 原子更新整型字段的更新器
- AtomicLongFieldUpdater 原子更新長(zhǎng)整型字段的更新器
- AtomicStampedReference 原子更新帶有版本號(hào)的引用類型哑蔫。該類將整數(shù)值與引用關(guān)聯(lián)起來(lái)钉寝,可用于解決原子的更新數(shù)據(jù)和數(shù)據(jù)的版本號(hào),可以解決使用 CAS 進(jìn)行原子更新時(shí)可能出現(xiàn)的 ABA 問(wèn)題鸳址。
所謂的CAS
的ABA
問(wèn)題:
2
我們選取上述四個(gè)類型的各一個(gè)原子類進(jìn)行源碼解讀瘩蚪,了解大概原理即可。
在原子類里稿黍,都是使用Unsafe
類進(jìn)行CAS
操作疹瘦,大家有時(shí)間可以看看Unsafe
類,雖然在Java9之后的版本被刪除了巡球,但是真的值得一看言沐。
2.1 AtomicInteger
說(shuō)簡(jiǎn)單點(diǎn),AtomicInteger
就是利用底層類無(wú)限循環(huán)進(jìn)行CAS
操作酣栈,直到成功為止险胰。
/**
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// 使用Unsafe.compareAndSwapInt進(jìn)行CAS更新操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 值偏移量
private static final long valueOffset;
/*
靜態(tài)塊初始化值偏移量
*/
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// 使用volatile修飾value 可以保證可見(jiàn)性和防止指令重排
private volatile int value;
/**
* 有參構(gòu)造,設(shè)置value = initialValue
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* 空構(gòu)造矿筝,value = 0
*/
public AtomicInteger() {}
/**
* 獲取當(dāng)前的value
*/
public final int get() {
return value;
}
/**
* 設(shè)置value值
*/
public final void set(int newValue) {
value = newValue;
}
/**
* 惰性設(shè)置value值
* unsafe.putOrderedInt() 不保證值的改變立即被其他線程看到
* 而lazySet()的用法就是在不需要讓共享變量的修改立刻讓其他線程可見(jiàn)的時(shí)候起便,以設(shè)置普通變量的方式來(lái)修改共享狀態(tài),可以減少不必要的內(nèi)存屏障窖维,從而提高程序執(zhí)行的效率榆综。
*/
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
/**
* 原子性的設(shè)置新值并返回舊值
*/
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
/**
* 如果當(dāng)前值等于expect(預(yù)期值),則原子性地將該值設(shè)置為給定的update(更新值)铸史。
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 如果當(dāng)前值等于expect(預(yù)期值)鼻疮,則原子性地將該值設(shè)置為給定的update(更新值)。
* 和上面的方法只是語(yǔ)義不同
* weakCompareAndSet無(wú)法保證處理操作目標(biāo)的volatile變量外的其他變量的執(zhí)行順序( 編譯器和處理器為了優(yōu)化程序性能而對(duì)指令序列進(jìn)行重新排序 )琳轿,同時(shí)也無(wú)法保證這些變量的可見(jiàn)性判沟。
*/
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 原子性地將當(dāng)前值加1,并返回舊值
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
/**
* 原子性地將當(dāng)前值減1崭篡,并返回舊值
*/
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
/**
* 原子性地將當(dāng)前值加delta挪哄,并返回舊值
*/
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
/**
* 原子性地將當(dāng)前值加1,并返回新值
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
/**
* 原子性地將當(dāng)前值減1媚送,并返回新值
*/
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
/**
* 原子性地將當(dāng)前值加delta中燥,并返回新值
*/
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值,并返回舊值塘偎。
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值疗涉,并返回新值拿霉。
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值,并返回舊值咱扣。
*
* IntBinaryOperator函數(shù)式接口:
*
* AtomicInteger.getAndAccumulate(3, (i, j) -> {
* // 通過(guò)給定的函數(shù)绽淘,返回要設(shè)置的結(jié)果
* return i * 10 * j
* });
* i是value
* j是3
*/
public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return prev;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值,并返回新值闹伪。
*
* IntBinaryOperator函數(shù)式接口:
*
* AtomicInteger.getAndAccumulate(3, (i, j) -> {
* // 通過(guò)給定的函數(shù)沪铭,返回要設(shè)置的結(jié)果
* return i * 10 * j
* });
* i是value
* j是3
*/
public final int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
/**
* Returns the String representation of the current value.
* @return the String representation of the current value
*/
public String toString() {
return Integer.toString(get());
}
/**
* 繼承自抽象類Number后,實(shí)現(xiàn)的抽象方法
*/
public int intValue() {
return get();
}
/**
* 繼承自抽象類Number后偏瓤,實(shí)現(xiàn)的抽象方法
*/
public long longValue() {
return (long)get();
}
/**
* 繼承自抽象類Number后杀怠,實(shí)現(xiàn)的抽象方法
*/
public float floatValue() {
return (float)get();
}
/**
* 繼承自抽象類Number后,實(shí)現(xiàn)的抽象方法
*/
public double doubleValue() {
return (double)get();
}
}
2.2 AtomicIntegerArray
原子性的更新數(shù)組里的某個(gè)元素厅克。
里面有幾段代碼寫(xiě)的很有意思赔退,值得玩味。
/**
* 整型數(shù)組元素原子性更新器
* @since 1.5
* @author Doug Lea
*/
public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L;
// 使用Unsafe類進(jìn)行CAS操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
// unsafe.arrayBaseOffset() 獲取數(shù)組第一個(gè)元素的偏移地址
private static final int base = unsafe.arrayBaseOffset(int[].class);
// 該類型的字節(jié)位移數(shù)
private static final int shift;
// 數(shù)組值
private final int[] array;
// 靜態(tài)塊
static {
// 獲取數(shù)組中元素的增量地址
int scale = unsafe.arrayIndexScale(int[].class);
// 按位與操作后 比較是否等于0证舟,如果不等于0硕旗,則拋出異常
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
// 就不在這里解釋這段代碼的含義了,觸及到了底層女责,有機(jī)會(huì)寫(xiě)一篇文章
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
// 檢查字節(jié)偏移量
private long checkedByteOffset(int i) {
// 快速判斷漆枚,如果
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
// 返回字節(jié)偏移量
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << shift) + base;
}
/**
* 有參構(gòu)造函數(shù),參數(shù)為數(shù)組長(zhǎng)度
* 并對(duì)array進(jìn)行初始化操作
*/
public AtomicIntegerArray(int length) {
array = new int[length];
}
/**
* 有參構(gòu)造函數(shù)抵知,參數(shù)為數(shù)組
* 并對(duì)參數(shù)array進(jìn)行克隆墙基,然后賦值給array
*/
public AtomicIntegerArray(int[] array) {
// Visibility guaranteed by final field guarantees
this.array = array.clone();
}
/**
* 返回?cái)?shù)組長(zhǎng)度
*/
public final int length() {
return array.length;
}
/**
* 獲取數(shù)組指定下標(biāo)的元素
*/
public final int get(int i) {
return getRaw(checkedByteOffset(i));
}
/**
* 私有方法
* 通過(guò)偏移量獲取數(shù)組元素
*/
private int getRaw(long offset) {
return unsafe.getIntVolatile(array, offset);
}
/**
* 設(shè)置數(shù)組指定下標(biāo)元素值
*/
public final void set(int i, int newValue) {
unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
}
/**
* 延遲設(shè)置數(shù)組指定下標(biāo)元素值
*/
public final void lazySet(int i, int newValue) {
unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
}
/**
* 原子性的設(shè)置數(shù)組指定元素值并返回舊值
*/
public final int getAndSet(int i, int newValue) {
return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue);
}
/**
* 進(jìn)行CAS操作設(shè)置數(shù)組指定下標(biāo)元素值
*/
public final boolean compareAndSet(int i, int expect, int update) {
return compareAndSetRaw(checkedByteOffset(i), expect, update);
}
private boolean compareAndSetRaw(long offset, int expect, int update) {
return unsafe.compareAndSwapInt(array, offset, expect, update);
}
/**
* 進(jìn)行CAS操作設(shè)置數(shù)組指定元素值
* 和上面的方法只是語(yǔ)義不同
* weakCompareAndSet無(wú)法保證處理操作目標(biāo)的volatile變量外的其他變量的執(zhí)行順序( 編譯器和處理器為了優(yōu)化程序性能而對(duì)指令序列進(jìn)行重新排序 ),同時(shí)也無(wú)法保證這些變量的可見(jiàn)性刷喜。
*/
public final boolean weakCompareAndSet(int i, int expect, int update) {
return compareAndSet(i, expect, update);
}
/**
* 原子性的對(duì)數(shù)組指定下標(biāo)的元素值加1碘橘,并返回舊值
*/
public final int getAndIncrement(int i) {
return getAndAdd(i, 1);
}
/**
* 原子性的對(duì)數(shù)組指定下標(biāo)的元素值減1,并返回舊值
*/
public final int getAndDecrement(int i) {
return getAndAdd(i, -1);
}
/**
* 原子性的對(duì)數(shù)組指定下標(biāo)的元素值加delta吱肌,并返回舊值
*/
public final int getAndAdd(int i, int delta) {
return unsafe.getAndAddInt(array, checkedByteOffset(i), delta);
}
/**
* 原子性的對(duì)數(shù)組指定下標(biāo)的元素值加1,并返回新值
*/
public final int incrementAndGet(int i) {
return getAndAdd(i, 1) + 1;
}
/**
* 原子性的對(duì)數(shù)組指定下標(biāo)的元素值減1仰禽,并返回新值
*/
public final int decrementAndGet(int i) {
return getAndAdd(i, -1) - 1;
}
/**
* 原子性的對(duì)數(shù)組指定下標(biāo)的元素值加delta氮墨,并返回新值
*/
public final int addAndGet(int i, int delta) {
return getAndAdd(i, delta) + delta;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新數(shù)組指定下標(biāo)的元素值,并返回舊值吐葵。
*/
public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = updateFunction.applyAsInt(prev);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新數(shù)組指定下標(biāo)的元素值规揪,并返回新值。
*/
public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = updateFunction.applyAsInt(prev);
} while (!compareAndSetRaw(offset, prev, next));
return next;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值温峭,并返回舊值猛铅。
*
* IntBinaryOperator函數(shù)式接口:
*
* atomicIntegerArray.getAndAccumulate(0, 3, (i, j) -> {
* log.info("i:" + i);
* log.info("j:" + j);
* return i + j;
* });
* i: 數(shù)組對(duì)應(yīng)下標(biāo)的元素值
* j: 3
*/
public final int getAndAccumulate(int i, int x, IntBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值,并返回新值凤藏。
*
* IntBinaryOperator函數(shù)式接口:
*
* atomicIntegerArray.getAndAccumulate(0, 3, (i, j) -> {
* log.info("i:" + i);
* log.info("j:" + j);
* return i + j;
* });
* i: 數(shù)組對(duì)應(yīng)下標(biāo)的元素值
* j: 3
*/
public final int accumulateAndGet(int i, int x, IntBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return next;
}
/**
* Returns the String representation of the current values of array.
* @return the String representation of the current values of array
*/
public String toString() {
int iMax = array.length - 1;
if (iMax == -1)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
}
}
2.3 AtomicReference
原子更新引用類型
/**
* 原子更新引用類型
* @since 1.5
* @author Doug Lea
* @param <V> The type of object referred to by this reference
*/
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
// 使用Unsafe類進(jìn)行CAS操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 值偏移地址
private static final long valueOffset;
// 靜態(tài)塊
static {
try {
// 計(jì)算值的偏移地址
valueOffset = unsafe.objectFieldOffset(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// 值奸忽,也就是我們要操作的值
private volatile V value;
/**
* 有參構(gòu)造
*/
public AtomicReference(V initialValue) {
value = initialValue;
}
/**
* 無(wú)參構(gòu)造
*/
public AtomicReference() {}
/**
* 獲取當(dāng)前值
*/
public final V get() {
return value;
}
/**
* 設(shè)置值
*/
public final void set(V newValue) {
value = newValue;
}
/**
* 惰性設(shè)置value值
*/
public final void lazySet(V newValue) {
unsafe.putOrderedObject(this, valueOffset, newValue);
}
/**
* 如果當(dāng)前值等于expect(預(yù)期值)堕伪,則原子性地將該值設(shè)置為給定的update(更新值)。
*/
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
/**
* 如果當(dāng)前值等于expect(預(yù)期值)栗菜,則原子性地將該值設(shè)置為給定的update(更新值)欠雌。
* 和上面的方法只是語(yǔ)義不同
* weakCompareAndSet無(wú)法保證處理操作目標(biāo)的volatile變量外的其他變量的執(zhí)行順序( 編譯器和處理器為了優(yōu)化程序性能而對(duì)指令序列進(jìn)行重新排序 ),同時(shí)也無(wú)法保證這些變量的可見(jiàn)性疙筹。
*/
public final boolean weakCompareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
/**
* 原子性的設(shè)置值并返回舊值
*/
@SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值富俄,并返回舊值。
*/
public final V getAndUpdate(UnaryOperator<V> updateFunction) {
V prev, next;
do {
prev = get();
next = updateFunction.apply(prev);
} while (!compareAndSet(prev, next));
return prev;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值而咆,并返回新值霍比。
*/
public final V updateAndGet(UnaryOperator<V> updateFunction) {
V prev, next;
do {
prev = get();
next = updateFunction.apply(prev);
} while (!compareAndSet(prev, next));
return next;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值,并返回舊值暴备。
*
* BinaryOperator函數(shù)式接口:
*
* atomicReference.getAndAccumulate(2, (i, j) -> {
* log.info("i:" + i);
* log.info("j:" + j);
* return i + j;
* });
* i: value
* j: 2
*/
public final V getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction) {
V prev, next;
do {
prev = get();
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSet(prev, next));
return prev;
}
/**
* 原子性地用給定函數(shù)的結(jié)果更新當(dāng)前值悠瞬,并返回新值。
*
* BinaryOperator函數(shù)式接口:
* atomicReference.getAndAccumulate(2, (i, j) -> {
* log.info("i:" + i);
* log.info("j:" + j);
* return i + j;
* });
* i: value
* j: 2
*/
public final V accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction) {
V prev, next;
do {
prev = get();
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
/**
* Returns the String representation of the current value.
* @return the String representation of the current value
*/
public String toString() {
return String.valueOf(get());
}
}
2.4 AtomicIntegerFieldUpdater
AtomicIntegerArray
要想原子地更新字段類需要如下過(guò)程
- 因?yàn)樵痈伦侄晤惗际浅橄箢愨裳保看问褂玫臅r(shí)候必須使用靜態(tài)方法 newUpdater() 創(chuàng)建一個(gè)更新器阁危,并且需要設(shè)置想要更新的類和屬性。
- 更新類的字段(屬性)必須使用
public
汰瘫、volatile
修飾符狂打,且變量類型只能用int
,不能使用Integer
混弥。
AtomicIntegerArray
就不貼源碼了趴乡,有點(diǎn)多,但是源碼不難蝗拿,看一看即可晾捏。貼一個(gè)使用的例子吧
@Slf4j
public class JunitTest {
@Setter
@Getter
@AllArgsConstructor
public class OrderTest {
public volatile int age;
}
@Test
public void test0() {
OrderTest orderTest = new OrderTest(18);
AtomicIntegerFieldUpdater orderTestUpdater = AtomicIntegerFieldUpdater.newUpdater(OrderTest.class, "age");
orderTestUpdater.incrementAndGet(orderTest);
orderTestUpdater.get(orderTest);
log.info("age: "+ orderTest.age);
}
}
輸出結(jié)果為:
age: 19