JMM中工作內(nèi)存和主內(nèi)存的關(guān)系

Java運行時的數(shù)據(jù)區(qū)域分布:

一有序、共享區(qū)域:

(1)方法區(qū):存儲了每個類的信息(包括類的名稱抹腿、方法信息、字段信息)旭寿、靜態(tài)變量警绩、常量以及編譯器編譯后的代碼等。其中常量池就是在此區(qū)域:記錄了每一個類或接口的常量池的運行時表示形式盅称,運行期間也可將新的常量放入運行時常量池中肩祥,比如String的intern方法。

(2)堆:jvm中最大的一片區(qū)域微渠,所有實例對象的內(nèi)存分配都在這里進行劃分。當(dāng)對象無法在此得到分配空間時咧擂,就會OutOfMemory逞盆。這部分空間也是Java垃圾收集器管理的主要區(qū)域。

二松申、線程私有:

(1)程序計數(shù)器:在JVM中云芦,多線程是通過線程輪流切換來獲得CPU執(zhí)行時間的,因此贸桶,在任一具體時刻舅逸,一個CPU的內(nèi)核只會執(zhí)行一條線程中的指令,因此皇筛,為了能夠使得每個線程都在線程切換后能夠恢復(fù)在切換之前的程序執(zhí)行位置琉历,每個線程都需要有自己獨立的程序計數(shù)器,并且不能互相被干擾水醋,否則就會影響到程序的正常執(zhí)行次序旗笔。因此,可以這么說拄踪,程序計數(shù)器是每個線程所私有的蝇恶。同時,如果線程數(shù)量太多惶桐,對于cpu來說就需要頻繁切換線程撮弧,導(dǎo)致cpu占有率上升潘懊。

(2)java棧:存放的是一個個的棧幀,每個棧幀對應(yīng)一個被調(diào)用的方法贿衍,在棧幀中包括局部變量表(Local Variables)授舟、操作數(shù)棧(Operand Stack)、指向當(dāng)前方法所屬的類的運行時常量池(運行時常量池的概念在方法區(qū)部分會談到)的引用(Reference to runtime constant pool)舌厨、方法返回地址(Return Address)和一些額外的附加信息岂却。

當(dāng)線程執(zhí)行一個方法時,就會隨之創(chuàng)建一個對應(yīng)的棧幀裙椭,并將建立的棧幀壓棧躏哩。當(dāng)方法執(zhí)行完畢之后,便會將棧幀出棧揉燃。因此可知扫尺,線程當(dāng)前執(zhí)行的方法所對應(yīng)的棧幀必定位于Java棧的頂部。當(dāng)程序設(shè)計時調(diào)用的棧的深度太深炊汤,有可能會導(dǎo)致無法創(chuàng)建棧幀正驻,導(dǎo)致OutOfMermory。

(3)本地棧:類似Java棧抢腐,但存放但是native方法的棧幀姑曙。

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

一、每個線程都有一個獨立的工作內(nèi)存迈倍,用于存儲線程私有的數(shù)據(jù)

二伤靠、Java內(nèi)存模型中規(guī)定所有變量都存儲在主內(nèi)存,主內(nèi)存是共享內(nèi)存區(qū)域啼染,所有線程都可以訪問

三宴合、線程對變量的操作(讀取賦值等)必須在工作內(nèi)存中進行。(線程安全問題的根本原因)

(1)首先要將變量從主內(nèi)存拷貝的自己的工作內(nèi)存空間

(2)然后對變量進行操作迹鹅,操作完成后再將變量寫回主內(nèi)存

(3)不能直接操作主內(nèi)存中的變量卦洽,工作內(nèi)存中存儲著主內(nèi)存中的變量副本拷貝

(4)因此不同的線程間無法訪問對方的工作內(nèi)存,線程間的通信(傳值)必須通過主內(nèi)存來完成斜棚。

主內(nèi)存和工作內(nèi)存

一阀蒂、主內(nèi)存是在運行期間所有變量的存放區(qū)域,當(dāng)工作內(nèi)存是運行期間中某一線程獨立私有的內(nèi)存存放區(qū)域

二弟蚀、線程間無法訪問對方的工作內(nèi)存空間脂新,都是通過主內(nèi)存交換來實現(xiàn)

三、主內(nèi)存的變量在工作內(nèi)存中的值是復(fù)制過去的副本粗梭,讀寫完成后刷新主內(nèi)存争便,這意味著主內(nèi)存如果發(fā)生了改變,工作內(nèi)存并無法獲得最新的結(jié)果

四断医、多個線程對一個共享變量進行修改時滞乙,都是對自己工作內(nèi)存的副本進行操作奏纪,相互不可見。主內(nèi)存最后得到的結(jié)果是不可預(yù)知的

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread1 is start斩启!");
                boolean wIsStop = false;
                while (!isStop) {

                }
                System.out.println("thread1 is going to stop!");
            }
        }).start();

上面這段代碼中序调,主線程改變isStop的變量后,是無法退出循環(huán)的兔簇。因為isStop這個變量在線程中從主內(nèi)存讀取到副本后发绢,一直使用的是工作內(nèi)存的副本。

Synchronized和Volatile

由于線程運行時垄琐,對工作內(nèi)存的變量進行操作時边酒,都是副本。
產(chǎn)生了兩個問題:
1.如何使工作內(nèi)存副本從主內(nèi)存獲取最新的值狸窘?
2.如何使其副本是最新避免在寫入之前被其他線程修改墩朦?

在主線程中改變了isStop=true后
下面這段代碼可以退出循環(huán):

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2 is start!");
                while (!isStop) {
                    synchronized(String.class) {

                    }
                }
                System.out.println("thread2 is going to stop!");
                System.out.println("break count: "  + count);
            }
        }).start();

或者是在while循環(huán)中加入了System.out.println的語句翻擒,也會退出循環(huán)氓涣。

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2 is start!");
                while (!isStop) {
                    System.out.println("thread2 stopFlag:" + isStop);
                }
                System.out.println("thread2 is going to stop!");
                System.out.println("break count: "  + count);
            }
        }).start();

其實System.out.println的實現(xiàn)中陋气,使用了Synchonized關(guān)鍵字獲取輸出對象的鎖劳吠。
一開始以為是Synchronized引起了工作內(nèi)存從主內(nèi)存刷新最新的數(shù)據(jù),感覺不太合理巩趁,后臺各種搜索后找到比較靠譜的答案:

jvm有一個鎖優(yōu)化原則那就是 : 粗化鎖痒玩。如果一系列的連續(xù)操作都對同一個對象反復(fù)加鎖和解鎖,甚至加鎖操作是出現(xiàn)在循環(huán)體中的晶渠,那即 使沒有線程競爭凰荚,頻繁地進行互斥同步操作也會導(dǎo)致不必要的性能損耗燃观。 如果虛擬機探測到有這樣一串零碎的操作都對同一個對象加鎖褒脯,將會把加鎖同步的范圍擴展(膨脹)到整個操作序列的外部(由多次加鎖編程只加鎖一次)。


====更新===
上面粗化鎖的解釋應(yīng)該也不準(zhǔn)確缆毁,鎖的對象并不是變量isStop番川,并不能將isStop加上一個線程可見的屬性。
在synchronized鎖操作中脊框,由于是一個耗時操作颁督,jvm會盡力在cpu空閑時間去主內(nèi)存同步工作內(nèi)存中變量的值。
====更新===

同樣下面的代碼浇雹,也能退出循環(huán):

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread3 is start沉御!");
                while (!isStop) {
                    try {
                        Thread.sleep(1);
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("thread3 is going to stop!");
            }
        }).start();

發(fā)現(xiàn)這個循環(huán)體里面并沒有synchronized的關(guān)鍵字,猜測只能是jvm在線程有空閑的時間盡力的去主存取最新數(shù)據(jù)昭灵。

引入Synchronized后吠裆,同步代碼塊在循環(huán)體內(nèi)伐谈,synchronized保證原子性和有序性,可見性试疙。

為了保證不同線程間可以獲得同一個共享變量诵棵,Volatile也可以做到。

volatile變量在每次被線程訪問時祝旷,都強迫從主內(nèi)存中讀該變量的值履澳,而當(dāng)該變量發(fā)生變化時,又會強迫將最新的值刷新到主內(nèi)存怀跛,任何時刻距贷,不同的線程總是能夠看到該變量的最新值。
上面代碼中敌完,對isStop用volatile修飾储耐,也可以退出線程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末滨溉,一起剝皮案震驚了整個濱河市什湘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晦攒,老刑警劉巖闽撤,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脯颜,居然都是意外死亡哟旗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門栋操,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闸餐,“玉大人,你說我怎么就攤上這事矾芙∩嵘常” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵剔宪,是天一觀的道長拂铡。 經(jīng)常有香客問我,道長葱绒,這世上最難降的妖魔是什么感帅? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮地淀,結(jié)果婚禮上失球,老公的妹妹穿的比我還像新娘针炉。我一直安慰自己胶征,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著看锉,像睡著了一般浩销。 火紅的嫁衣襯著肌膚如雪妈经。 梳的紋絲不亂的頭發(fā)上临梗,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音荧止,去河邊找鬼屹电。 笑死,一個胖子當(dāng)著我的面吹牛跃巡,可吹牛的內(nèi)容都是我干的危号。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼素邪,長吁一口氣:“原來是場噩夢啊……” “哼外莲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兔朦,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤偷线,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沽甥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體声邦,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年摆舟,在試婚紗的時候發(fā)現(xiàn)自己被綠了亥曹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡恨诱,死狀恐怖媳瞪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情照宝,我是刑警寧澤蛇受,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站硫豆,受9級特大地震影響龙巨,放射性物質(zhì)發(fā)生泄漏笼呆。R本人自食惡果不足惜熊响,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诗赌。 院中可真熱鬧汗茄,春花似錦、人聲如沸铭若。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞳腌,卻和暖如春绞铃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嫂侍。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工儿捧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挑宠。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓菲盾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親各淀。 傳聞我的和親對象是個殘疾皇子懒鉴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

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