Atomic 翻譯成中文是原子的意思。在化學(xué)上,我們知道原子是構(gòu)成一般物質(zhì)的最小單位,在化學(xué)反應(yīng)中是不可分割的。在我們這里 Atomic 是指一個(gè)操作是不可中斷的。即使是在多個(gè)線程一起執(zhí)行的時(shí)候,一個(gè)操作一旦開(kāi)始,就不會(huì)被其他線程干擾。所以,所謂原子類(lèi)說(shuō)簡(jiǎn)單點(diǎn)就是具有原子/原子操作特征的類(lèi)。并發(fā)包 java.util.concurrent 的原子類(lèi)都存放在 java.util.concurrent.atomic 下,如下圖所示。
根據(jù)操作的數(shù)據(jù)類(lèi)型,可以將JUC包中的原子類(lèi)分為4類(lèi)
基本類(lèi)型
使用原子的方式更新基本類(lèi)型
AtomicInteger:整型原子類(lèi)
AtomicLong:長(zhǎng)整型原子類(lèi)
AtomicBoolean :布爾型原子類(lèi)
數(shù)組類(lèi)型
使用原子的方式更新數(shù)組里的某個(gè)元素
AtomicIntegerArray:整型數(shù)組原子類(lèi)
AtomicLongArray:長(zhǎng)整型數(shù)組原子類(lèi)
AtomicReferenceArray :引用類(lèi)型是數(shù)組原子類(lèi)
引用類(lèi)型
AtomicReference:引用類(lèi)型原子類(lèi)
AtomicMarkableReference:原子更新帶有標(biāo)記的引用類(lèi)型。該類(lèi)將 boolean 標(biāo)記與引用關(guān)聯(lián)起來(lái),也可以解決使用 CAS 在進(jìn)行原子更新時(shí)可能出現(xiàn)的 ABA 問(wèn)題。
AtomicStampedReference :原子更新帶有版本號(hào)的引用類(lèi)型。該類(lèi)將整數(shù)值與引用關(guān)聯(lián)起來(lái),可用于解決原子的更新數(shù)據(jù)和數(shù)據(jù)的版本號(hào),可以解決使用 CAS 進(jìn)行原子更新時(shí)可能出現(xiàn)的 ABA問(wèn)題。
對(duì)象的屬性修改類(lèi)型
AtomicIntegerFieldUpdater:原子更新整型字段的更新器
AtomicLongFieldUpdater:原子更新長(zhǎng)整型字段的更新器
AtomicReferenceFieldUpdater:原子更新引用類(lèi)型里的字段
修正: AtomicMarkableReference 不能解決ABA問(wèn)題
/**AtomicMarkableReference是將一個(gè)boolean值作是否有更改的標(biāo)記,本質(zhì)就是它的版本號(hào)只有兩個(gè),true和false,修改的時(shí)候在這兩個(gè)版本號(hào)之間來(lái)回切換,這樣做并不能解決ABA的問(wèn)題,只是會(huì)降低ABA問(wèn)題發(fā)生的幾率而已
*/
public class SolveABAByAtomicMarkableReference {
private static AtomicMarkableReference atomicMarkableReference = new
AtomicMarkableReference(100, false);
public static void main(String[] args) {
Thread refT1 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicMarkableReference.compareAndSet(100, 101,
atomicMarkableReference.isMarked(), !atomicMarkableReference.isMarked());
atomicMarkableReference.compareAndSet(101, 100,
atomicMarkableReference.isMarked(), !atomicMarkableReference.isMarked());
});
Thread refT2 = new Thread(() -> {
boolean marked = atomicMarkableReference.isMarked();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean c3 = atomicMarkableReference.compareAndSet(100, 101,
marked, !marked);
System.out.println(c3); // 返回true,實(shí)際應(yīng)該返回false
});
refT1.start();
refT2.start();
}
}
CAS ABA 問(wèn)題
描述: 第一個(gè)線程取到了變量 x 的值 A,然后巴拉巴拉干別的事,總之就是只拿到了變量 x 的值A(chǔ)。這段時(shí)間內(nèi)第二個(gè)線程也取到了變量 x 的值 A,然后把變量 x 的值改為 B,然后巴拉巴拉干別的事,最后又把變量 x 的值變?yōu)?A (相當(dāng)于還原了)。在這之后第一個(gè)線程終于進(jìn)行了變量 x 的操作,但是此時(shí)變量 x 的值還是 A,所以 compareAndSet 操作是成功。例子描述(可能不太合適,但好理解): 年初,現(xiàn)金為零,然后通過(guò)正常勞動(dòng)賺了三百萬(wàn),之后正常消費(fèi)了(比如買(mǎi)房子)三百萬(wàn)。年末,雖然現(xiàn)金零收入(可能變成其他形式了),但是賺了錢(qián)是事實(shí),還是得交稅的!
代碼例子(以 AtomicInteger 為例)
【關(guān)注】轉(zhuǎn)發(fā)了解更多內(nèi)容,方便后續(xù)查看