JAVA內(nèi)存模型與線程

Java內(nèi)存模型

Java內(nèi)存模型的主要目標(biāo)是定義程序中各個(gè)變量的訪問(wèn)規(guī)則喊式,即JVM中將變量存儲(chǔ)到內(nèi)存中和從內(nèi)存中取出變量這樣的底層細(xì)節(jié)锌奴,變量包括了實(shí)例字段兽狭、靜態(tài)字段和構(gòu)成數(shù)組對(duì)象的元素,但是不包括局部變量和方法參數(shù),內(nèi)存模型規(guī)定了所有的變量都必須存儲(chǔ)在主內(nèi)存箕慧,線程對(duì)變量的所有操作(取值服球、賦值)都必須在內(nèi)存中完成。

內(nèi)存模型定義了8種操作來(lái)完成工作內(nèi)存和主內(nèi)存之間的實(shí)現(xiàn)細(xì)節(jié)颠焦,而且這幾種操作都是原子的斩熊、不可再分的(64位的double和long類型除外),線程伐庭、工作內(nèi)存和主內(nèi)存之間交互如下圖所示:


線程粉渠、工作內(nèi)存與主內(nèi)存交互圖

lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占的狀態(tài)圾另。
unlock(解鎖):作用于主內(nèi)存的變量,將一個(gè)鎖定狀態(tài)的變量釋放出來(lái)霸株,釋放的變量可由其他線程鎖定。
read(讀燃恰):作用于主內(nèi)存的變量去件,把一個(gè)變量從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的load使用饺著。
load(載入):作用于工作內(nèi)存的變量箫攀,把read操作從主內(nèi)存中讀取的變量放入工作內(nèi)存的變量副本中。
use(使用):作用于工作內(nèi)存的變量幼衰,把工作內(nèi)存中的值傳遞給執(zhí)行引擎靴跛,每當(dāng)jvm遇到一個(gè)需要使用變量的值的字節(jié)碼指令就執(zhí)行這個(gè)操作。
assign(賦值):作用于工作內(nèi)存的變量,把執(zhí)行引擎接收到的值賦給工作內(nèi)存中的變量渡嚣,每當(dāng)jvm遇到一個(gè)需要給變量賦值的字節(jié)碼指令就執(zhí)行這個(gè)操作梢睛。
store(存儲(chǔ)):作用于工作內(nèi)存的變量,把工作內(nèi)存中的值傳輸?shù)街鲀?nèi)存中,供之后的write操作使用识椰。
write(寫(xiě)入):作用于主內(nèi)存的變量,把store操作傳入的變量的值放入主內(nèi)存中的變量中绝葡。

主內(nèi)存->工作內(nèi)存 read->load
工作內(nèi)存->主內(nèi)存 store->write
上述操作必須按順序執(zhí)行,但是并不一定需要連續(xù)執(zhí)行腹鹉。
針對(duì)以上操作需滿足以下幾個(gè)規(guī)則:
(1)不允許read,load,store和write單獨(dú)出現(xiàn)
(2)不允許一個(gè)線程丟棄最近的assign操作
(3)一個(gè)新變量只能在內(nèi)存中誕生
(4)一個(gè)變量在同一個(gè)時(shí)刻只允許一個(gè)線程進(jìn)行l(wèi)ock操作
(5)不允許一個(gè)線程沒(méi)有assign操作將數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存
(6)如果線程對(duì)一個(gè)變量進(jìn)行l(wèi)ock操作藏畅,將會(huì)把工作內(nèi)存中的數(shù)據(jù)清空。功咒,需要重新load或assgin變量的值愉阎。
(7)對(duì)一個(gè)變量進(jìn)行unlock操作之前,必須將數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存(執(zhí)行store力奋,write操作)

對(duì)volatile變量的特殊規(guī)則

JVM提供的最輕量級(jí)的同步機(jī)制榜旦,它具備以下2種特性:
(1)保證此變量對(duì)所有線程的可見(jiàn)性,但并不保證并發(fā)安全景殷,java里面的運(yùn)算并非原子操作溅呢,所以volatile修飾的變量在并發(fā)條件下不能保證線程安全澡屡。
底層原理:java的++操作,編譯后由4條字節(jié)碼指令(多條機(jī)器碼指令)構(gòu)成:
a.getstatic
b.iconst_1
c.iadd
d.putstatic
在執(zhí)行iconst_1,iadd指令時(shí)咐旧,可能其他線程已經(jīng)修改了操作棧頂?shù)闹凳火模瑢?dǎo)致pustatic執(zhí)行時(shí),把已經(jīng)過(guò)期的數(shù)據(jù)(比實(shí)際數(shù)據(jù)行菖肌)同步回主內(nèi)存梁厉。
演示代碼:

public class VolatileTest {

    private static volatile int count = 0;

    
    public static void main(String[] args) {

        VolatileTest volatileTest = new VolatileTest();

        for (int i = 0; i < 10000; i++) {

            new Thread(new Runnable() {
                @Override
                public void run() {
                    count++;
                }
            }).start();
        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println("累加結(jié)果:" + count);
    }
}
image.png

反編譯后的++操作字節(jié)碼:


image.png

預(yù)期結(jié)果應(yīng)該是10000,但是實(shí)際結(jié)果是9996踏兜,說(shuō)明在累加過(guò)程中把過(guò)期的值同步回了主內(nèi)存。
volatile的使用場(chǎng)景:
a.運(yùn)算結(jié)果不依賴變量當(dāng)前計(jì)算的值或者能夠確保只有單一線程能夠修改線程的值
b.變量不需要與其他狀態(tài)變量共同參與不變約束(只需要一個(gè)變量就可以控制并發(fā))

(2)禁止指令重排序優(yōu)化
有volatile修飾的變量八秃,賦值后多執(zhí)行了一個(gè)"lock"操作碱妆,這個(gè)操作相當(dāng)于一個(gè)內(nèi)存屏障(指令重排序時(shí)不能將后面的指令重排序到內(nèi)存屏障之前的位置),該指令使得本cpu的cache寫(xiě)入內(nèi)存昔驱,同時(shí)會(huì)引起其他CPU或者別的內(nèi)核無(wú)效化其cache,相當(dāng)于做了"store和write操作"疹尾,因而使得volatile修飾的變量的修改對(duì)其他CPU立即可見(jiàn)。

線程并發(fā)過(guò)程中的原子性骤肛、有序性和可見(jiàn)性

原子性:基本數(shù)據(jù)類型的訪問(wèn)讀寫(xiě)是具備原子性的纳本,原子性變量操作包括read、load腋颠、assign繁成、use、store和write.
(1)synchroniozed關(guān)鍵字淑玫,底層由字節(jié)碼指令monitorenter和monitorexit實(shí)現(xiàn)巾腕。
(2)lock和unlock操作
可見(jiàn)性:當(dāng)一個(gè)線程修改了共享變量的值,其他線程能夠立即得知這個(gè)修改絮蒿。

有序性:在本線程中觀察尊搬,所有操作都是有序的;如果在一個(gè)線程中觀察另外一個(gè)線程土涝,所有操作都是無(wú)序的佛寿。

Java與線程

(1)線程的實(shí)現(xiàn)
a.使用內(nèi)核線程實(shí)現(xiàn)
直接由操作系統(tǒng)內(nèi)核支持的線程,內(nèi)核通過(guò)調(diào)度器對(duì)線程進(jìn)行調(diào)度但壮,將線程任務(wù)反映到各個(gè)處理器上.
b.使用用戶線程實(shí)現(xiàn)
不是內(nèi)核線程的線程
c.使用用戶線程和輕量級(jí)進(jìn)程實(shí)現(xiàn)
輕量級(jí)進(jìn)程由內(nèi)核線程支持冀泻,內(nèi)核線程與輕量級(jí)進(jìn)程是1:1的關(guān)系,進(jìn)程與用戶線程是1:N的關(guān)系,輕量級(jí)進(jìn)程與用戶線程是N:M的關(guān)系;SunJDK使用1:1的線程模型實(shí)現(xiàn)茵肃。

(2)Java線程調(diào)度
a.協(xié)同式線程調(diào)度
線程的執(zhí)行時(shí)間由自己控制腔长,線程把工作完成之后,要主動(dòng)通知操作系統(tǒng)切換到另外一個(gè)線程验残,缺點(diǎn)是一個(gè)線程阻塞會(huì)導(dǎo)致整個(gè)進(jìn)程阻塞捞附,好處是實(shí)現(xiàn)簡(jiǎn)單。
b.搶占式線程調(diào)度
每個(gè)線程由系統(tǒng)來(lái)分配執(zhí)行時(shí)間,JAVA使用搶占式調(diào)度鸟召,通過(guò)設(shè)置線程優(yōu)先級(jí)(1-10)可由設(shè)置指定線程分配更多執(zhí)行時(shí)間胆绊,優(yōu)先級(jí)高的線程會(huì)被操作系統(tǒng)優(yōu)先執(zhí)行。
(3)狀態(tài)切換
Java語(yǔ)言定義了5種線程狀態(tài).


image.png
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末欧募,一起剝皮案震驚了整個(gè)濱河市压状,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌跟继,老刑警劉巖种冬,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異舔糖,居然都是意外死亡娱两,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)金吗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)十兢,“玉大人,你說(shuō)我怎么就攤上這事摇庙『滴铮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵卫袒,是天一觀的道長(zhǎng)宵呛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)玛臂,這世上最難降的妖魔是什么烤蜕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮迹冤,結(jié)果婚禮上讽营,老公的妹妹穿的比我還像新娘。我一直安慰自己泡徙,他們只是感情好橱鹏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著堪藐,像睡著了一般莉兰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上礁竞,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天糖荒,我揣著相機(jī)與錄音,去河邊找鬼模捂。 笑死捶朵,一個(gè)胖子當(dāng)著我的面吹牛蜘矢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播综看,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼品腹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了红碑?” 一聲冷哼從身側(cè)響起舞吭,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎析珊,沒(méi)想到半個(gè)月后羡鸥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忠寻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年兄春,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锡溯。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖哑姚,靈堂內(nèi)的尸體忽然破棺而出祭饭,到底是詐尸還是另有隱情,我是刑警寧澤叙量,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布倡蝙,位于F島的核電站,受9級(jí)特大地震影響绞佩,放射性物質(zhì)發(fā)生泄漏寺鸥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一品山、第九天 我趴在偏房一處隱蔽的房頂上張望胆建。 院中可真熱鬧,春花似錦肘交、人聲如沸笆载。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)凉驻。三九已至,卻和暖如春复罐,著一層夾襖步出監(jiān)牢的瞬間涝登,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工效诅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胀滚,地道東北人趟济。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蛛淋,于是被迫代替她去往敵國(guó)和親咙好。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 除了充分利用計(jì)算機(jī)處理器的能力外褐荷,一個(gè)服務(wù)端同時(shí)對(duì)多個(gè)客戶端提供服務(wù)則是另一個(gè)更具體的并發(fā)應(yīng)用場(chǎng)景勾效。衡量一個(gè)服務(wù)性...
    胡二囧閱讀 1,340評(píng)論 0 12
  • 1. 緩存一致性 計(jì)算機(jī)并發(fā)執(zhí)行若干任務(wù),需要與內(nèi)存交互叛甫。計(jì)算機(jī)存儲(chǔ)設(shè)備處理速度與處理器處理速度有著量級(jí)的差距层宫,所...
    sizuoyi00閱讀 352評(píng)論 0 0
  • 1.概述 讓計(jì)算機(jī)同時(shí)做幾件事,一個(gè)很重要的原因是計(jì)算機(jī)的運(yùn)算速度與它的存儲(chǔ)和通信子系統(tǒng)速度差距太大其监,大量的時(shí)間花...
    過(guò)來(lái)摸摸頭丶閱讀 432評(píng)論 0 1
  • 注:此文是我在讀完周志明老師的深入理解Java虛擬機(jī)之后總結(jié)的一篇文章萌腿,請(qǐng)閱讀此書(shū)獲取更加詳細(xì)的信息. 在介紹Ja...
    AlstonWilliams閱讀 386評(píng)論 0 1
  • 一、內(nèi)存模型 1. 主內(nèi)存與工作內(nèi)存 虛擬機(jī)運(yùn)行時(shí)內(nèi)存區(qū)域: 虛擬機(jī)內(nèi)存模型 前者內(nèi)存區(qū)域中的Java堆抖苦、棧毁菱、方法...
    路遠(yuǎn)處幽閱讀 425評(píng)論 0 0