Java高并發(fā)編程學(xué)習(xí)筆記(二)-并發(fā)基礎(chǔ)

1.CPU多級(jí)緩存

左圖為最簡(jiǎn)單的高速緩存的配置锌唾,數(shù)據(jù)的讀取和存儲(chǔ)都經(jīng)過高速緩存搏色,CPU核心與高速緩存有一條特殊的快速通道仰猖;主存與高速緩存都連在系統(tǒng)總線上(BUS)這條總線還用于其他組件的通信

在高速緩存出現(xiàn)后不久,系統(tǒng)變得越來越復(fù)雜神得,高速緩存與主存之間的速度差異被拉大厘惦,直到加入了另一級(jí)緩存,新加入的這級(jí)緩存比第一緩存更大循头,并且更慢绵估,而且經(jīng)濟(jì)上不合適,所以有了二級(jí)緩存卡骂,甚至是三級(jí)緩存

CPU多級(jí)緩存

為什么需要CPU cache国裳?:

CPU的頻率太快了,快到主存跟不上全跨,這樣在處理器時(shí)鐘周期內(nèi)缝左,CPU常常需要等待主存渺杉,浪費(fèi)資源是越,

所以cache的出現(xiàn)倚评,是為了緩解CPU和內(nèi)存之間速度的不匹配問題(結(jié)構(gòu):cpu->cache->memort)

CPU cache有什么意義:

1.時(shí)間局部性:如果某個(gè)數(shù)據(jù)被訪問,那么在不久的將來他很可能被再次訪問

2.空間局部性:如果某個(gè)數(shù)據(jù)被訪問呢岗,那么與他相鄰的數(shù)據(jù)很快也可能被訪問

緩存一致性(MESI)

? M: Modified 修改后豫,指的是該緩存行只被緩存在該CPU的緩存中挫酿,并且是被修改過的饭豹,因此他與主存中的數(shù)據(jù)是不一致的,

? ? ? 該緩存行中的數(shù)據(jù)需要在未來的某個(gè)時(shí)間點(diǎn)(允許其他CPU讀取主存相應(yīng)中的內(nèi)容之前)寫回主存翘悉,然后狀態(tài)變成E(獨(dú)享)

? E:Exclusive 獨(dú)享 緩存行只被緩存在該CPU的緩存中妖混,是未被修改過的,與主存的數(shù)據(jù)是一致的祥楣,可以在任何時(shí)刻當(dāng)有其他CPU讀取該內(nèi)存時(shí)误褪,變成S(共享)狀態(tài),當(dāng)CPU修改該緩存行的內(nèi)容時(shí)嘀略,變成M(被修改)的狀態(tài)

? S:Share 共享,意味著該緩存行可能會(huì)被多個(gè)CPU進(jìn)行緩存逮壁,并且該緩存中的數(shù)據(jù)與主存數(shù)據(jù)是一致的卖宠,當(dāng)有一個(gè)CPU修改該緩存行時(shí)扛伍,其他CPU是可以被作廢的刺洒,變成I(無效的)

? I:Invalid 無效的逆航,代表這個(gè)緩存是無效的,可能是有其他CPU修改了該緩存行

1.用于保證多個(gè)CPU cache之間緩存共享數(shù)據(jù)的一致

MESI

local read:讀本地緩存的數(shù)據(jù)

local write:將數(shù)據(jù)寫到本地緩存里面

remote read:將內(nèi)(主)存中的數(shù)據(jù)讀取到緩存中來

remote write:將緩存中的數(shù)據(jù)寫會(huì)到主存里面

在一個(gè)典型的多核系統(tǒng)中,每一個(gè)核都會(huì)有自己的緩存來共享主存總線澳眷,每一個(gè)CPU會(huì)發(fā)出讀寫(I/O)請(qǐng)求境蔼,而緩存的目的是為了減少CPU讀寫共享主存的次數(shù);

一個(gè)緩存除了在Invaild狀態(tài)吴藻,都可以滿足CPU 的讀請(qǐng)求

一個(gè)寫請(qǐng)求只有在M狀態(tài),或者E狀態(tài)的時(shí)候才能給被執(zhí)行航罗,如果是處在S狀態(tài)的時(shí)候粥血,他必須先將該緩存行變成I狀態(tài)趾娃,

這個(gè)操作通常作用于廣播的方式來完成,這個(gè)時(shí)候他既不允許不同的CPU同時(shí)修改同一個(gè)緩存行笤成,即使是修改同一個(gè)緩存行中不同端的數(shù)據(jù)也是不可以的,這里主要解決的是緩存一致性的問題,

一個(gè)M狀態(tài)的緩存行必須時(shí)刻監(jiān)聽所有試圖讀該緩存行相對(duì)主存的操作,這種操作必須在緩存該緩存行被寫會(huì)到主存,并將狀態(tài)變成S狀態(tài)之前掉蔬,被延遲執(zhí)行

一個(gè)處于S狀態(tài)的緩存行,也必須監(jiān)聽其他緩存使該緩存行無效蛉迹,或者獨(dú)享該緩存行的請(qǐng)求,并將緩存行變成無效

一個(gè)處于E狀態(tài)的緩存行,他要監(jiān)聽其他緩存讀緩存行的操作攘宙,一旦有肩民,那么他講變成S狀態(tài)

因此對(duì)于M和E狀態(tài),他們的數(shù)據(jù)總是一致的與緩存行的真正狀態(tài)總是保持一致的工窍,

但是S狀態(tài)可能是非一致的罢维,如果一個(gè)緩存將處于S狀態(tài)的 緩存行作廢了匀借,另一個(gè)緩存可能已經(jīng)獨(dú)享了該緩存行,

但是該緩存缺不會(huì)講該緩存行升遷為E狀態(tài),這是因?yàn)槠渌彺娌粫?huì)廣播他們已經(jīng)作廢掉該緩存行的通知,

同樣由于緩存并沒有保存該緩存行被COPY的數(shù)量,因此沒有辦法確定是否獨(dú)享了改緩存行紫皇,

這是一種投機(jī)性的優(yōu)化萄窜,因?yàn)槿绻粋€(gè)CPU想修改一個(gè)處于S狀態(tài)的緩存行键兜,總線需要將所有使用該緩存行的COPY的值變成Invaild狀態(tài)才可以,而修改E狀態(tài)的緩存缺不需要使用總顯示無

2.CPU多級(jí)緩存的亂序執(zhí)行優(yōu)化

處理器為提高運(yùn)算速度而做出違背代碼原有順序的優(yōu)化

CPU亂序

導(dǎo)致的一個(gè)問題仔沿,如果我們不做任何處理,在多核的情況下,的實(shí)際結(jié)果可能和邏輯運(yùn)行結(jié)果大不相同脊阴,如果在一個(gè)核上執(zhí)行數(shù)據(jù)寫入操作,并在最后執(zhí)行一個(gè)操作來標(biāo)記數(shù)據(jù)已經(jīng)寫入好了蜜猾,而在另外一個(gè)核上通過該標(biāo)記位判定數(shù)據(jù)是否已經(jīng)寫入,這時(shí)候就可能出現(xiàn)不一致脊串,標(biāo)記位先被寫入怖侦,但是實(shí)際的操作缺并未完成念赶,這個(gè)未完成既有可能是沒有計(jì)算完成础钠,也有可能是緩存沒有被及時(shí)刷新到主存之中,使得其他核讀到了錯(cuò)誤的數(shù)據(jù)

3.Java內(nèi)存模型(Java Memory Model叉谜,JMM)

JAVA內(nèi)存模型規(guī)范:

1.規(guī)定了一個(gè)線程如何和何時(shí)可以看到其他線程修改過后的共享變量的值

2.如何以及何時(shí)同步的訪問共享變量

JAVA內(nèi)存模型:

java內(nèi)存分配

Heap(堆):java里的堆是一個(gè)運(yùn)行時(shí)的數(shù)據(jù)區(qū)旗吁,堆是由垃圾回收來負(fù)責(zé)的,? ? ? ? 堆的優(yōu)勢(shì)是可以動(dòng)態(tài)的分配內(nèi)存大小停局,生存期也不必事先告訴編譯器很钓,? ? ? ? 因?yàn)樗窃谶\(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存的,java的垃圾回收器會(huì)定時(shí)收走不用的數(shù)據(jù)董栽,? ? ? ? 缺點(diǎn)是由于要在運(yùn)行時(shí)動(dòng)態(tài)分配码倦,所有存取速度可能會(huì)慢一些Stack(棧):棧的優(yōu)勢(shì)是存取速度比堆要快,僅次于計(jì)算機(jī)里的寄存器锭碳,棧的數(shù)據(jù)是可以共享的袁稽,? ? ? ? ? 缺點(diǎn)是存在棧中的數(shù)據(jù)的大小與生存期必須是確定的,缺乏一些靈活性? ? ? ? ? 棧中主要存放一些基本類型的變量擒抛,比如int推汽,short,long歧沪,byte歹撒,double,float诊胞,boolean暖夭,char,對(duì)象句柄撵孤,java內(nèi)存模型要求調(diào)用棧和本地內(nèi)存變量存放在線程棧(Thread Stack)上迈着,對(duì)象存放在堆上。一個(gè)本地變量可能存放一個(gè)對(duì)象的引用邪码,這時(shí)引用變量存放在本地棧上寥假,但是對(duì)象本身存放在堆上成員變量跟隨著對(duì)象存放在堆上,而不管是原始類型還是引用類型霞扬,靜態(tài)成員變量跟隨著類的定義一起存在在堆上存在堆上的對(duì)象糕韧,可以被持有這個(gè)對(duì)象的引用的線程訪問如果兩個(gè)線程同時(shí)訪問同一個(gè)對(duì)象的私有變量枫振,這時(shí)他們獲得的是這個(gè)對(duì)象的私有拷貝

計(jì)算機(jī)硬件架構(gòu):

計(jì)算機(jī)架構(gòu)圖示

CPU:一個(gè)計(jì)算機(jī)一般有多個(gè)CPU,一個(gè)CPU還會(huì)有多核

CPU Registers(寄存器):每個(gè)CPU都包含一系列的寄存器萤彩,他們是CPU內(nèi)存的基礎(chǔ)粪滤,CPU在寄存器上執(zhí)行的速度遠(yuǎn)大于在主存上執(zhí)行的速度。

CPU Cache(高速緩存):由于計(jì)算機(jī)的存儲(chǔ)設(shè)備與處理器的處理設(shè)備有著幾個(gè)數(shù)量級(jí)的差距雀扶,

? ? ? ? ? ? ? ? ? ? 所以現(xiàn)代計(jì)算機(jī)都會(huì)加入一層讀寫速度與處理器處理速度接近想通的高級(jí)緩存來作為內(nèi)存與處理器之間的緩沖杖小,

? ? ? ? ? ? ? ? ? ? 將運(yùn)算使用到的數(shù)據(jù)復(fù)制到緩存中,讓運(yùn)算能夠快速的執(zhí)行愚墓,當(dāng)運(yùn)算結(jié)束后予权,再?gòu)木彺嫱降絻?nèi)存之中,這樣浪册,CPU就不需要等待緩慢的內(nèi)存讀寫了

主(內(nèi))存:一個(gè)計(jì)算機(jī)包含一個(gè)主存扫腺,所有的CPU都可以訪問主存,主存比緩存容量大的多

運(yùn)作原理:通常情況下村象,當(dāng)一個(gè)CPU要讀取主存的時(shí)候笆环,他會(huì)將主存中的數(shù)據(jù)讀取到CPU緩存中,甚至將緩存中的內(nèi)容讀到內(nèi)部寄存器里面厚者,然后再寄存器執(zhí)行操作躁劣,

當(dāng)運(yùn)行結(jié)束后,會(huì)將寄存器中的值刷新回緩存中库菲,并在某個(gè)時(shí)間點(diǎn)刷新回主存

內(nèi)存模型與硬件架構(gòu)之間的關(guān)聯(lián):

內(nèi)存模型與硬件架構(gòu)之間的關(guān)聯(lián)

所有線程棧和堆會(huì)被保存在緩存里面账忘,部分可能會(huì)出現(xiàn)在CPU緩存中和CPU內(nèi)部的寄存器里面

線程和主內(nèi)存的抽象關(guān)系

線程和主內(nèi)存的抽象關(guān)系

每個(gè)線程之間共享變量都存放在主內(nèi)存里面,每個(gè)線程都有一個(gè)私有的本地內(nèi)存

本地內(nèi)存是java內(nèi)存模型中抽象的概念熙宇,并不是真實(shí)存在的(他涵蓋了緩存寫緩沖區(qū)鳖擒。寄存器,以及其他硬件的優(yōu)化)

本地內(nèi)存中存儲(chǔ)了以讀或者寫共享變量的拷貝的一個(gè)副本

從一個(gè)更低的層次來說奇颠,線程本地內(nèi)存败去,他是cpu緩存放航,寄存器的一個(gè)抽象描述烈拒,而JVM的靜態(tài)內(nèi)存存儲(chǔ)模型,

他只是一種對(duì)內(nèi)存模型的物理劃分而已广鳍,只局限在內(nèi)存荆几,而且只局限在JVM的內(nèi)存

如果線程A和線程B要通信,必須經(jīng)歷兩個(gè)過程:

1赊时、A將本地內(nèi)存變量刷新到主內(nèi)存

2吨铸、B從主內(nèi)存中讀取變量

八種同步操作

1.lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)識(shí)變?yōu)橐粭l線程獨(dú)占狀態(tài)

2.unlock(解鎖):作用于主內(nèi)存的變量祖秒,把一個(gè)處于鎖定狀態(tài)的變量釋放出來诞吱,釋放后的變量才可以被其他線程鎖定

3.read(讀戎鄣臁):作用于主內(nèi)存的變量,把一個(gè)變量值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中房维,以便隨后的load動(dòng)作使用

4.load(載入):作用于工作內(nèi)存的變量沼瘫,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中

5.use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量值傳遞給執(zhí)行引擎

6.assign(賦值):作用于工作內(nèi)存的變量咙俩,它把一個(gè)從執(zhí)行引擎接受到的值賦值給工作內(nèi)存的變量

7.store(存儲(chǔ)):作用于工作內(nèi)存的變量耿戚,把工作內(nèi)存中的一個(gè)變量的值傳送到主內(nèi)存中,以便隨后的write的操作

8.write(寫入):作用于主內(nèi)存的變量阿趁,它把store操作從工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存的變量中

同步規(guī)則

1.如果要把一個(gè)變量從主內(nèi)存中賦值到工作內(nèi)存膜蛔,就需要按順序得執(zhí)行read和load操作,如果把變量從工作內(nèi)存中同步回主內(nèi)存中脖阵,就要按順序得執(zhí)行store和write操作皂股,但java內(nèi)存模型只要求上述操作必須按順序執(zhí)行,沒有保證必須是連續(xù)執(zhí)行

2.不允許read和load独撇、store和write操作之一單獨(dú)出現(xiàn)

3.不允許一個(gè)線程丟棄他的最近assign的操作屑墨,即變量在工作內(nèi)存中改變了之后必須同步到主內(nèi)存中

4.不允許一個(gè)線程無原因地(沒有發(fā)生過任何assign操作)把數(shù)據(jù)從工作內(nèi)存同步到主內(nèi)存中

5.一個(gè)新的變量只能在主內(nèi)存中誕生,不允許在工作內(nèi)存中直接使用一個(gè)未被初始化(load或assign)的變量纷铣。即就是對(duì)一個(gè)變量實(shí)施use和store操作之前卵史,必須先執(zhí)行過了load和assign操作

6.一個(gè)變量在同一時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作,但lock操作可以同時(shí)被一條線程重復(fù)執(zhí)行多次搜立,多次執(zhí)行l(wèi)ock后以躯,只有執(zhí)行相同次數(shù)的unlock操作,變量才會(huì)解鎖啄踊,lock和unlock必須成對(duì)出現(xiàn)

7.如果一個(gè)變量執(zhí)行l(wèi)ock操作忧设,將會(huì)清空工作內(nèi)存中此變量的值,在執(zhí)行引擎中使用這個(gè)變量前需要重新執(zhí)行l(wèi)oad或assign操作初始化變量的值

8.如果一個(gè)變量事先沒有被lock操作鎖定颠通,則不允許他執(zhí)行unlock操作址晕,也不允許去unlock一個(gè)被其他線程鎖定的變量

9.對(duì)一個(gè)變量執(zhí)行unlock操作之前,必須先把此變量同步到主內(nèi)存中(執(zhí)行store和write操作)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顿锰,一起剝皮案震驚了整個(gè)濱河市谨垃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌硼控,老刑警劉巖刘陶,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異牢撼,居然都是意外死亡匙隔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門熏版,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纷责,“玉大人捍掺,你說我怎么就攤上這事≡偕牛” “怎么了乡小?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)饵史。 經(jīng)常有香客問我满钟,道長(zhǎng),這世上最難降的妖魔是什么胳喷? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任湃番,我火速辦了婚禮,結(jié)果婚禮上吭露,老公的妹妹穿的比我還像新娘吠撮。我一直安慰自己,他們只是感情好讲竿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布泥兰。 她就那樣靜靜地躺著,像睡著了一般题禀。 火紅的嫁衣襯著肌膚如雪鞋诗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天迈嘹,我揣著相機(jī)與錄音削彬,去河邊找鬼。 笑死秀仲,一個(gè)胖子當(dāng)著我的面吹牛融痛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播神僵,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼雁刷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了保礼?” 一聲冷哼從身側(cè)響起沛励,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氓英,沒想到半個(gè)月后侯勉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹦筹,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铝阐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铐拐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徘键。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡练对,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吹害,到底是詐尸還是另有隱情螟凭,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布它呀,位于F島的核電站螺男,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏纵穿。R本人自食惡果不足惜下隧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谓媒。 院中可真熱鬧淆院,春花似錦、人聲如沸句惯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抢野。三九已至拷淘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間指孤,已是汗流浹背辕棚。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留邓厕,地道東北人逝嚎。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像详恼,于是被迫代替她去往敵國(guó)和親补君。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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