Java CAS機(jī)制的一些理解
多線(xiàn)程實(shí)踐
public class test {
private static int x;
public static void main(String[] args) throws InterruptedException {
Thread task1 = new Thread(){
@Override
public void run() {
super.run();
for (int i=0; i<1000; i++){
x=x+1;
}
}
};
Thread task2 = new Thread(){
@Override
public void run() {
super.run();
for (int i=0; i<1000; i++){
x=x+1;
}
}
};
task1.start();
task2.start();
task1.join();
task2.join();
System.out.println(x);
}
/*
1006
*///:~
兩個(gè)線(xiàn)程同時(shí)開(kāi)啟,累加x,理想的情況下,輸出應(yīng)該是2000,但是最終是1006,因?yàn)槭嵌嗑€(xiàn)程的情況下,一次累加可能是兩個(gè)線(xiàn)程同時(shí)完成的。
public class test {
private static AtomicInteger atomicInteger = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
Thread task1 = new Thread(){
@Override
public void run() {
super.run();
for (int i=0; i<1000; i++){
atomicInteger.incrementAndGet();
}
}
};
Thread task2 = new Thread(){
@Override
public void run() {
super.run();
for (int i=0; i<1000; i++){
atomicInteger.incrementAndGet();
}
}
};
task1.start();
task2.start();
task1.join();
task2.join();
System.out.println(atomicInteger.get());
}
}/*
2000
*///:~
修改被累加對(duì)象x為AtomicInteger,最終結(jié)果是理想的2000。在此操作中并沒(méi)有使用鎖,原因是 AtomicInteger引入了CAS機(jī)制。
什么是CAS機(jī)制
CAS機(jī)制簡(jiǎn)單的說(shuō)就是,比較交換,有預(yù)期值、舊值和內(nèi)存位置;取出舊值,交換新值。
為何AtomicInteger線(xiàn)程安全
源碼:
private static final long valueOffset;
...
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
...
Unsafe
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
unsafe提供了硬件級(jí)別的原子操作 valueOffset是變量?jī)?nèi)存地址 從源碼可以看出,incrementAndGet是調(diào)用了unsafe.getAndAddInt,它是一種基于CAS機(jī)制實(shí)現(xiàn)的,var5是從主內(nèi)存中獲取最新當(dāng)前值,而這個(gè)值是所有線(xiàn)程都可見(jiàn)和共享的,與var4相加交換,如果失敗就一直自旋,直到更新值成功。
圖解CAS機(jī)制

可以看出來(lái),CAS沒(méi)有使用了任何鎖,就完成了線(xiàn)程安全。 CAS的優(yōu)點(diǎn)很多,但是缺點(diǎn)也很多,比如ABA問(wèn)題
ABA問(wèn)題
什么是ABA問(wèn)題
其實(shí)很好理解,A->B->A,A值雖然沒(méi)有變,但是已經(jīng)經(jīng)過(guò)了某種操作。
圖解

有什么影響
上面的線(xiàn)程1、2、3都完成它們自己的任務(wù),并沒(méi)有問(wèn)題。但是如果它們是在轉(zhuǎn)賬,問(wèn)題就打了,賬戶(hù)就無(wú)端端的不見(jiàn)了10塊錢(qián)。
解決
引入版本號(hào),可以解決問(wèn)題,每次有相同的值時(shí),做一次版本累加,只要是版本號(hào)對(duì)不上就是被修改過(guò)

總結(jié)
優(yōu)點(diǎn): 在并發(fā)量不是很高的情況,避免了鎖帶來(lái)的消耗
缺點(diǎn):
- 并發(fā)量高的情況下,如果多次修改不成功,一直循環(huán)修改,就會(huì)帶來(lái)cpu的持續(xù)消耗
- 只能對(duì)變量進(jìn)行原子級(jí)別的安全修改,不能對(duì)代碼塊進(jìn)行安全操作。
以上就是Java CAS機(jī)制的一些理解的詳細(xì)內(nèi)容,更多關(guān)于Java CAS機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JDK線(xiàn)程池和Spring線(xiàn)程池的使用實(shí)例解析
這篇文章主要介紹了JDK線(xiàn)程池和Spring線(xiàn)程池的使用實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí)實(shí)例
這篇文章主要為大家介紹了Go?Java算法之為運(yùn)算表達(dá)式設(shè)計(jì)優(yōu)先級(jí)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
myeclipse安裝Spring Tool Suite(STS)插件的方法步驟
這篇文章主要介紹了myeclipse安裝Spring Tool Suite(STS)插件的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
遞歸出現(xiàn)棧溢出stackoverflow的問(wèn)題及解決
這篇文章主要介紹了關(guān)于遞歸出現(xiàn)棧溢出stackoverflow的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Mybatis使用@Select注解sql中使用in問(wèn)題
這篇文章主要介紹了Mybatis使用@Select注解sql中使用in問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
selenium4.0版本在springboot中的使用問(wèn)題的坑
本文主要介紹了selenium4.0版本在springboot中的使用問(wèn)題的坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
SpringBoot實(shí)現(xiàn)過(guò)濾敏感詞的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用SpringBoot實(shí)現(xiàn)過(guò)濾敏感詞功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-08-08

