Java內(nèi)存模型

主內(nèi)存間與工作內(nèi)存

Java內(nèi)存模型規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存中,每條線程有自己的工作內(nèi)存

線程、主內(nèi)存、工作內(nèi)存三者的交互關(guān)系

內(nèi)存間交互操作

  • lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占的狀態(tài)
  • unlock(解鎖):作用于主內(nèi)存的變量,把一個(gè)處于鎖定狀態(tài)的變量釋放出來,釋放后的變量才可以被其他線程鎖定
  • read(讀?。鹤饔糜谥鲀?nèi)存的變量,把一個(gè)變量的值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的load動(dòng)作使用
  • use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中一個(gè)變量的值傳遞給執(zhí)行引擎
  • assign(賦值):作用于工作內(nèi)存的變量,把一個(gè)從執(zhí)行引擎接受到的值賦給工作內(nèi)存的變量
  • store(存儲(chǔ)):作用于工作內(nèi)存的變量,把工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存中
  • write(寫入):作用于主內(nèi)存的變量,把store操作從工作內(nèi)存得到的變量的值放入主內(nèi)存的變量中
內(nèi)存交互操作

volatile關(guān)鍵字

volatile關(guān)鍵字可以說是Java虛擬機(jī)提供的最輕量級(jí)的同步機(jī)制,但是它并不容易完全被正確、完整地理解,以至于很多程序員都不習(xí)慣使用它,遇到多線程數(shù)據(jù)競(jìng)爭(zhēng)問題的時(shí)候就一律使用synchronized來進(jìn)行同步。了解volatile變量的語義對(duì)了解多線程操作的很多特性很有意義。

  • volatile的可見性:保證此變量對(duì)所有線程的可見性,但不意味著是立即可見的
public class Counter {
 
    public volatile static int count = 0;
 
    public static void inc() {
          count++;
    }
 
    public static void main(String[] args) { 
        //同時(shí)啟動(dòng)1000個(gè)線程,去進(jìn)行i++計(jì)算,看看實(shí)際結(jié)果 
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                }
            }).start();
        }
 
        //這里每次運(yùn)行的值都有可能不同,可能為1000
        System.out.println("運(yùn)行結(jié)果:Counter.count=" + Counter.count);
    }
}

在本例中count變量用volatile關(guān)鍵字進(jìn)行修飾,保證了線程均可以取到count變量,但是由于count++是一個(gè)非原子操作(下一小節(jié)介紹),這個(gè)操作需要執(zhí)行4條指令才能完成,在此期間如果有另一個(gè)線程進(jìn)行讀取操作,隨后原來的線程會(huì)將數(shù)據(jù)寫入,另一個(gè)線程又會(huì)進(jìn)行寫入。例如第一個(gè)線程讀取count的時(shí)候,count=20,在執(zhí)行++操作的時(shí)候,有另一個(gè)線程讀取count,此時(shí)count尚未完成++,所以值還是20。在后一個(gè)線程進(jìn)行操作時(shí),前一個(gè)線程執(zhí)行完,將count寫入21,當(dāng)后一個(gè)線程完成后,仍舊寫入21, 所以本該寫入22的數(shù)值就這樣變小了。

  • volatile的禁止指令重排序優(yōu)化

相比于synchronized,volatile總開銷要小,這是由于volatile變量的讀操作性能消耗與普通變量差不多,寫操作可能會(huì)慢一點(diǎn)。

原子性、可見性和有序性

原子性(Atomicity)

由Java內(nèi)存模型來直接保證的原子性變量操作包括read、load、assign、use、store、write,基本數(shù)據(jù)類型的訪問讀寫是具備原子性的(long和double是例外)。synchronized使用了lock和unlock操作,所以synchronized塊之間的操作也具有原子性。

可見性(Visibility)

可見性是指當(dāng)一個(gè)線程修改了共享變量的值,其他線程能夠立即得知這個(gè)修改。無論是普通變量還是volatile變量都是如此,區(qū)別是volatile的特殊規(guī)則保證了新值能立即同步到主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新。volatile保證了多線程操作時(shí)變量的可見性,而普通變量則不能保證這一點(diǎn)。synchronized和final也能夠?qū)崿F(xiàn)可見性。

有序性(Ordering)

volatile和synchronized保證線程之間操作的有序性

最后編輯于
?著作權(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)容