原子操作

總線鎖(CPU總線):

CPU芯片上有一條引線#HLOCK pin,如果匯編語(yǔ)言的程序中在一條指令前面加上前綴"LOCK",經(jīng)過(guò)匯編以后的機(jī)器代碼就使CPU在執(zhí)行這條指令的時(shí)候把#HLOCK pin的電位拉低,持續(xù)到這條指令結(jié)束時(shí)放開(kāi),從而把總線鎖住,這樣同一總線上別的CPU就暫時(shí)不能通過(guò)總線訪問(wèn)內(nèi)存了,保證了這條指令在多處理器環(huán)境中的原子性.

緩存鎖:

頻繁使用的內(nèi)存會(huì)緩存在處理器的L1,L2和L3高速緩存里,那么原子操作就可以直接在處理器內(nèi)部緩存中進(jìn)行,并不需要聲明總線鎖。

所謂“緩存鎖定”就是如果緩存在處理器緩存行中內(nèi)存區(qū)域在LOCK操作期間被鎖定,當(dāng)它執(zhí)行鎖操作回寫內(nèi)存時(shí),處理器不在總線上聲言LOCK#信號(hào),而是修改內(nèi)部的內(nèi)存地址,并允許它的緩存一致性機(jī)制(當(dāng)某塊CPU對(duì)緩存中的數(shù)據(jù)進(jìn)行操作了之后,就通知其他CPU放棄儲(chǔ)存在它們內(nèi)部的緩存,或者從主內(nèi)存中重新讀取)來(lái)保證操作的原子性.

JAVA原子操作:

在java中可以通過(guò)鎖和循環(huán)CAS(compare and swap)的方式來(lái)實(shí)現(xiàn)原子操作。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class T {

    public static void main(String[] args) {

        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            threads.add(new Thread(new MyThread()));
        }

        for (Thread t : threads) {
            t.start();
        }

        for (Thread t : threads) {
            try {
                t.join();
            } catch (InterruptedException e) {
            }
        }

        System.out.println("counter_i:" + MyThread.counter_i);
        System.out.println("counter_volatile:" + MyThread.counter_volatile);
        System.out.println("counter_automic:" + MyThread.counter_cas.get());
        System.out.println("counter_locker:" + MyThread.counter_locker);
    }

}

class MyThread implements Runnable {

    static int counter_i;
    static volatile int counter_volatile;
    static AtomicInteger counter_cas;
    static int counter_locker;

    static {
        counter_cas = new AtomicInteger(0);
        counter_i = 0;
        counter_volatile = 0;
        counter_locker = 0;
    }

    @Override
    public void run() {
        // 未保證原子型操作
        counter_i++;
        // 未保證原子型操作
        counter_volatile++;

        int i;
        do {
            // 保證了原子型操作
            i = counter_cas.get();
        } while (!counter_cas.compareAndSet(i, ++i));

        // 保證了原子型操作
        synchronized (MyThread.class) {
            counter_locker++;
        }

    }

}

分析:

線程中i++可拆解成如下操作:
a. 從主存復(fù)制變量到線程本地內(nèi)存
b. 讀取線程本地內(nèi)存i
c. 線程本地內(nèi)存i+1
d. 寫回線程本地內(nèi)存
e. 用線程本地內(nèi)存數(shù)據(jù)刷新主存相關(guān)內(nèi)容

直接i++有很多種case會(huì)出現(xiàn)問(wèn)題

分析略

volatile i ++

雖然告訴JVM當(dāng)前變量在寄存器/高速緩存(工作內(nèi)存)中的值是不確定的,需要從主存中讀取), 使修改對(duì)其他線程可見(jiàn),但是仍然沒(méi)有作到i++的原子操作. volatile無(wú)法保證復(fù)合操作的原子性。

AtomicInteger 循環(huán)使用CAS

基于處理器CMPXCHG,保證了原子性. Java的AtomicInteger使用上面提到的系統(tǒng)級(jí)別的總線鎖和緩存鎖來(lái)保證原子操作。
AtomicInteger最終調(diào)用

//object:操作的對(duì)象
//address:操作對(duì)象的屬性地址
//expected:預(yù)期值
//newValue:新值
compareAndSwapInt(Object object, long address, int expected, int newValue) 

CAS有幾個(gè)缺點(diǎn):

  • ABA:
    例如有鏈表 A->B
    線程1 compareAndSet(A,B), compare A 之前, 線程2 將鏈表結(jié)構(gòu)變?yōu)锳->C,線程1compare A OK(A地址未變化),并Swap A和 B,鏈表結(jié)構(gòu)變?yōu)锽,和預(yù)期的B->A不同.
    解決辦法:使用版本戳,java 中的AtomicStampedReference實(shí)現(xiàn)了該功能。
  • 循環(huán)時(shí)間長(zhǎng)
  • 只能操作一個(gè)變量
    解決辦法:將多個(gè)變量封裝在一個(gè)對(duì)象中,使用AtomicReference<V>。
synchronized 對(duì)i++操作整體加鎖,保證了原子性.

synchronized關(guān)鍵字強(qiáng)制實(shí)施一個(gè)互斥鎖,使得被保護(hù)的代碼塊在同一時(shí)間只能有一個(gè)線程進(jìn)入并執(zhí)行。當(dāng)然synchronized還有另外一個(gè) 方面的作用:在線程進(jìn)入synchronized塊之前,會(huì)把工作存內(nèi)存中的所有內(nèi)容映射到主內(nèi)存上,然后把工作內(nèi)存清空再?gòu)闹鞔鎯?chǔ)器上拷貝最新的值。而 在線程退出synchronized塊時(shí),同樣會(huì)把工作內(nèi)存中的值映射到主內(nèi)存,但此時(shí)并不會(huì)清空工作內(nèi)存。這樣一來(lái)就可以強(qiáng)制其按照上面的順序運(yùn)行,以 保證線程在執(zhí)行完代碼塊后,工作內(nèi)存中的值和主內(nèi)存中的值是一致的,保證了數(shù)據(jù)的一致性!

參考資料:

原子操作的實(shí)現(xiàn)原理
關(guān)于單CPU,多CPU上的原子操作
聊聊并發(fā)(五)——原子操作的實(shí)現(xiàn)原理
CAS原理分析
java 里面保留字volatile及其與synchronized的區(qū)別

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容