線程安全性

概述

?當(dāng)多個(gè)線程訪問某個(gè)類時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式,并且在主調(diào)代碼中不需要額外的同步,這個(gè)類都能表現(xiàn)出正確的行為,那么這個(gè)類就是線程安全的。線程安全體現(xiàn)在三個(gè)方面:原子性、可見性和有序性。

原子性

?一個(gè)操作是不可中斷的,要么全部執(zhí)行成功,要么全部執(zhí)行失敗。當(dāng)多個(gè)線程工作時(shí),一個(gè)操作一旦開始,就不會(huì)被其他線程干擾。
?Java中實(shí)現(xiàn)原子性操作的兩種方式:Atomic包 和 鎖
?Atomic是基于CAS實(shí)現(xiàn)的,下面以AtomicInteger為例。

    AtomicInteger是含有一個(gè)int類型的值,這個(gè)類的作用是原子性的更新。事物都是一分為
二的,AtomicInteger雖然支持原子性的操作,但是其并不能代替Integer類。該類繼承自
Number。
    以getAndSet(int newValue) 方法為例解釋。
    該方法:原子性的賦新值,并且返回舊值。
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
    該類調(diào)用了Unsafe類的getAndSetInt方法

    Unsafe的getAndSetInt方法
    public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            //第一處
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var4));//第二處

        return var5;
    }

    參數(shù)var1 就是傳入的AtomicInteger實(shí)例
    參數(shù)var2 就是傳入的valueOffset值,valueOffset是屬性的偏移量,Unsafe就是通過valueOffset值獲取實(shí)際值。
    參數(shù)var4 就是傳入的newValue,預(yù)設(shè)值的新值。
    
    第一處 通過對(duì)象和偏移量,原子性的獲取了值。并且將這個(gè)值返回。
    第二處 調(diào)用了compareAndSwapInt方法。CAS。設(shè)置成功之后 跳出循環(huán)。
    
    compareAndSwapInt(var1, var2, var5, var4)原理
    
    var5是舊值(期望的值), var4是新值, var1和var2配合可以求出內(nèi)存中的值
    
    如果內(nèi)存值與var5(期望的值)相一致,那么就將內(nèi)存的值設(shè)置為var4。并且返回true。
    如果內(nèi)存值與var5不一致,那么就返回false。
    

?鎖在java中有兩種實(shí)現(xiàn)方式:synchronized關(guān)鍵字和Lock類。
?synchronized修飾的對(duì)象
??修飾代碼塊,作用于調(diào)用的對(duì)象

synchronized{
    
}

??修飾方法,作用于調(diào)用的對(duì)象

public synchronized int add(int a,int b){
        return a+b;
}

??修飾靜態(tài)方法,作用于所有對(duì)象

public synchronized static int add(int a,int b){
        return a+b;
}

??修飾類,作用于所有對(duì)象

 synchronized (Test.class){

}

可見性

?當(dāng)一個(gè)線程修改了共享變量的值后,另一個(gè)線程可以立即看到修改后的值。


image

?共享變量不可見的原因:
??共享變量更新后的值沒有在工作內(nèi)存與主內(nèi)存之間及時(shí)更新。
?內(nèi)存可見性實(shí)現(xiàn)的方式:
??synchronized關(guān)鍵字和volatile關(guān)鍵字

?synchronized關(guān)鍵字內(nèi)存可見性的原因:
??①線程解鎖前,必須把共享變量的最新值刷新到主內(nèi)存中。
??②線程加鎖時(shí),將清空工作內(nèi)存中共享變量的值,從而使用共享變量時(shí),需要從主內(nèi)存中重新讀取最新的值。

?volatile關(guān)鍵字內(nèi)存可見性的原因:通過內(nèi)存屏障和禁止重排序?qū)崿F(xiàn)的
??①volatile會(huì)在寫操作時(shí),會(huì)在寫操作后加一條store屏障指令,將本地內(nèi)存中的共享變量值刷新到主內(nèi)存
??②volatile在進(jìn)行讀操作時(shí),會(huì)在讀操作前加一條load指令,從內(nèi)存中讀取共享變量。

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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