jvm內(nèi)存模型與原子性甜滨,可見(jiàn)性乐严,有序性

一.內(nèi)存模型:

  • 每一個(gè)線程有一個(gè)工作內(nèi)存,和主存是獨(dú)立的衣摩。
  • 工作內(nèi)存存放主存重變量的值得拷貝

線程獨(dú)享的工作內(nèi)存和主存的關(guān)系昂验,如下圖:


image.png
  1. 當(dāng)數(shù)據(jù)從主內(nèi)存復(fù)制到工作存儲(chǔ)時(shí),必須出現(xiàn)兩個(gè)動(dòng)作:第一艾扮,由主內(nèi)存執(zhí)行的讀(read)操作既琴;第二,由工作內(nèi)存執(zhí)行的相應(yīng)的load操作泡嘴;
  2. 當(dāng)數(shù)據(jù)從工作內(nèi)存拷貝到主內(nèi)存時(shí)甫恩,也出現(xiàn)兩個(gè)操作:第一個(gè),由工作內(nèi)存執(zhí)行的存儲(chǔ)(store)操作磕诊;第二填物,由主內(nèi)存執(zhí)行的相應(yīng)的寫(xiě)(write)操作。
  3. 每一個(gè)操作都是原子的霎终,即執(zhí)行期間不會(huì)被中斷滞磺,即read不會(huì)中斷,但是read和load直接會(huì)有中斷莱褒。
  4. 對(duì)于普通變量击困,一個(gè)線程中更新的值,不能馬上反應(yīng)在其他變量中广凸。如果需要在其他線程中立即可見(jiàn)阅茶,需要使用 volatile 關(guān)鍵字。
image.png

jmm控制共享變量和共享變量副本直接的拷貝谅海,基于cpu優(yōu)化的原因脸哀,會(huì)有一定程度的延遲。

二.原子性:

原子性是指一個(gè)操作是不可中斷的扭吁。即使是在多個(gè)線程一起執(zhí)行的時(shí)候撞蜂,一個(gè)操作一旦開(kāi)始盲镶,就不會(huì)被其他線程干擾。
i++是原子操作嗎蝌诡?
不是溉贿。i++由三個(gè)原子操作組成:

  1. 線程私有內(nèi)存從主存把i的值拷貝下來(lái)。
  2. 執(zhí)行i++操作浦旱。
  3. 把i的值賦給主存宇色。

三.可見(jiàn)性

可見(jiàn)性是指當(dāng)一個(gè)線程修改了某一個(gè)共享變量的值,其他線程是否能夠立即知道這個(gè)修改颁湖。
– 編譯器優(yōu)化
– 硬件優(yōu)化(如寫(xiě)吸收宣蠕,批操作)


image.png

這幅圖展示了發(fā)生可見(jiàn)性問(wèn)題的一種可能。如果在CPU1和CPU2

volatile:
volatile修飾的變量爷狈,在主內(nèi)存和線程私有內(nèi)存直接拷貝不會(huì)有延遲植影。

public class VolatileStopThread extends  Thread {
    private volatile boolean stop=false;
    public void stepMe(){
        stop=true;
    }

    public void run(){
        int i=0;
        while (!stop){
            i++;
        }
        System.out.println("Stop thread");
    }

    public static void main(String[] args) throws InterruptedException{
        VolatileStopThread t=new VolatileStopThread();
        t.start();//子線程
        Thread.sleep(1000);
        t.stepMe();//主線程
        Thread.sleep(1000);
    }
}

volatile 不能代替鎖

  • 一般認(rèn)為volatile比鎖性能好(不絕對(duì))
  • 選擇使用volatile的條件是:語(yǔ)義是否滿足應(yīng)用。
  • 沒(méi)有volatile -server運(yùn)行 無(wú)法停止涎永,因?yàn)閂olatileStopThread只在線程的本地存儲(chǔ)區(qū)查看stop的值思币。
  • 可見(jiàn)性:一個(gè)線程修改了變量,其他線程可以立即知道羡微。
  • 保證可見(jiàn)性的方法:
    1. volatile
    2. synchronized(unlock之前谷饿,寫(xiě)變量值回主存)
    3. final(一旦初始化完成,其他線程就可見(jiàn))妈倔。

四.有序性:

在并發(fā)時(shí)博投,程序的執(zhí)行可能會(huì)出現(xiàn)亂序。
1.在本線程內(nèi)盯蝴,操作都是有序的毅哗。(不會(huì)破壞語(yǔ)義,所以看似有序)
2.在線程外觀察捧挺,操作都是無(wú)序的虑绵。(造成原因:1.指令重排。2.主內(nèi)存同步延遲--可見(jiàn)性)

class OrderExample {
int a = 0;
boolean flag = false;

public void writer() {
  a = 1;                   
  flag = true;           
}

public void reader() {
  if (flag) {                
      int i =  a +1;      
      ……
  }
}
}

線程A首先執(zhí)行writer()方法
線程B線程接著執(zhí)行reader()方法
線程B在int i=a+1 是不一定能看到a已經(jīng)被賦值為1
因?yàn)樵趙riter中闽烙,兩句話順序可能打亂:
線程A
flag=true
a=1

線程B
flag=true;在a = 1;之前執(zhí)行翅睛。(此時(shí)a=0) 就是說(shuō)flag=true;和a = 1;這兩行很難預(yù)料誰(shuí)先執(zhí)行。

如何保證有序呢:加synchronized同步,同步后黑竞,即使做了writer重排捕发,因?yàn)榛コ獾木壒剩瑀eader 線程看writer線程也是順序執(zhí)行的很魂。

class OrderExample {
int a = 0;
boolean flag = false;

public synchronized void writer() {
    a = 1;                   
    flag = true;           
}

public synchronized void reader() {
    if (flag) {                
        int i =  a +1;      
        ……
    }
}
}
  • 指令重排:編譯器為了使性能優(yōu)化扎酷,編譯器會(huì)將代碼指令的順序進(jìn)行調(diào)整。保證線程內(nèi)串行語(yǔ)義遏匆,不保證多線程直接的語(yǔ)義霞玄。如:
    寫(xiě)后讀 a=1;b=a; 寫(xiě)一個(gè)變量后骤铃,再讀這個(gè)位置。
    寫(xiě)后寫(xiě) a=1;a=2; 寫(xiě)一個(gè)變量后坷剧,再寫(xiě)這個(gè)變量
    讀后寫(xiě) a=b;b=1; 讀一個(gè)變量后,再讀這個(gè)變量喊暖。
    以上語(yǔ)句不能重排惫企。
    編譯器不考慮多線程間的語(yǔ)義。
    可重拍:a=1;b=2;

指令重排的基本原則:

  • 程序順序原則:一個(gè)線程內(nèi)保證語(yǔ)義的串行性
  • volatile規(guī)則:volatile變量的寫(xiě)陵叽,先發(fā)生于讀
  • 鎖規(guī)則:解鎖(unlock)必然發(fā)生在隨后的加鎖(lock)前
  • 傳遞性:A指令先于B指令狞尔,B指令先于C指令 那么A指令必然先于C指令
  • 線程的start方法先于它的每一個(gè)動(dòng)作
  • 線程的所有操作先于線程的終結(jié)(Thread.join())
  • 線程的中斷(interrupt())先于被中斷線程的代碼
  • 對(duì)象的構(gòu)造函數(shù)執(zhí)行結(jié)束先于finalize()方法
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市巩掺,隨后出現(xiàn)的幾起案子偏序,更是在濱河造成了極大的恐慌,老刑警劉巖胖替,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件研儒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡独令,警方通過(guò)查閱死者的電腦和手機(jī)端朵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)燃箭,“玉大人冲呢,你說(shuō)我怎么就攤上這事≌欣辏” “怎么了敬拓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)裙戏。 經(jīng)常有香客問(wèn)我乘凸,道長(zhǎng),這世上最難降的妖魔是什么挽懦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任翰意,我火速辦了婚禮,結(jié)果婚禮上信柿,老公的妹妹穿的比我還像新娘冀偶。我一直安慰自己,他們只是感情好渔嚷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布进鸠。 她就那樣靜靜地躺著,像睡著了一般形病。 火紅的嫁衣襯著肌膚如雪客年。 梳的紋絲不亂的頭發(fā)上霞幅,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音量瓜,去河邊找鬼司恳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绍傲,可吹牛的內(nèi)容都是我干的扔傅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼烫饼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼猎塞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起杠纵,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤荠耽,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后比藻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體铝量,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年韩容,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了款违。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡群凶,死狀恐怖插爹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情请梢,我是刑警寧澤赠尾,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站毅弧,受9級(jí)特大地震影響气嫁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜够坐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一寸宵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧元咙,春花似錦梯影、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至赶掖,卻和暖如春感猛,著一層夾襖步出監(jiān)牢的瞬間七扰,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工陪白, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颈走,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓咱士,卻偏偏與公主長(zhǎng)得像疫鹊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子司致,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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