摘要:緩存行也必須監(jiān)聽其它緩存使該緩存行無效或者獨(dú)享該緩存行的請(qǐng)求,并將該緩存行變成無效。無注意對(duì)于和狀態(tài)而言總是精確的,他們?cè)诤驮摼彺嫘械恼嬲隣顟B(tài)是一致的,而狀態(tài)可能是非一致的。多線程并發(fā)的優(yōu)勢(shì)和缺點(diǎn)
CPU緩存一致性協(xié)議MESI
CPU在摩爾定律的指導(dǎo)下以每18個(gè)月翻一番的速度在發(fā)展,然而內(nèi)存和硬盤的發(fā)展速度遠(yuǎn)遠(yuǎn)不及CPU。這就造成了高性能能的內(nèi)存和硬盤價(jià)格及其昂貴。然而CPU的高度運(yùn)算需要高速的數(shù)據(jù)。為了解決這個(gè)問題,CPU廠商在CPU中內(nèi)置了少量的高速緩存以解決IO速度和CPU運(yùn)算速度之間的不匹配問題。
在CPU訪問存儲(chǔ)設(shè)備時(shí),無論是存取數(shù)據(jù)抑或存取指令,都趨于聚集在一片連續(xù)的區(qū)域中,這就被稱為局部性原理。
時(shí)間局部性(Temporal Locality):如果一個(gè)信息項(xiàng)正在被訪問,那么在近期它很可能還會(huì)被再次訪問。
比如循環(huán)、遞歸、方法的反復(fù)調(diào)用等。
空間局部性(Spatial Locality):如果一個(gè)存儲(chǔ)器的位置被引用,那么將來他附近的位置也會(huì)被引用。
比如順序執(zhí)行的代碼、連續(xù)創(chuàng)建的兩個(gè)對(duì)象、數(shù)組等
程序以及數(shù)據(jù)被加載到主內(nèi)存
指令和數(shù)據(jù)被加載到CPU的高速緩存
CPU執(zhí)行指令,把結(jié)果寫到高速緩存
高速緩存中的數(shù)據(jù)寫回主內(nèi)存
MESI協(xié)議緩存狀態(tài)
緩存行(Cache line):緩存存儲(chǔ)數(shù)據(jù)的單元。
狀態(tài) | 描述 | 監(jiān)聽任務(wù) |
---|---|---|
M 修改 (Modified) | 該Cache line有效,數(shù)據(jù)被修改了,和內(nèi)存中的數(shù)據(jù)不一致,數(shù)據(jù)只存在于本Cache中。 | 緩存行必須時(shí)刻監(jiān)聽所有試圖讀該緩存行相對(duì)就主存的操作,這種操作必須在緩存將該緩存行寫回主存并將狀態(tài)變成S(共享)狀態(tài)之前被延遲執(zhí)行。 |
E 獨(dú)享、互斥 (Exclusive) | 該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)只存在于本Cache中。 | 緩存行也必須監(jiān)聽其它緩存讀主存中該緩存行的操作,一旦有這種操作,該緩存行需要變成S(共享)狀態(tài)。 |
S 共享 (Shared) | 該Cache line有效,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致,數(shù)據(jù)存在于很多Cache中。 | 緩存行也必須監(jiān)聽其它緩存使該緩存行無效或者獨(dú)享該緩存行的請(qǐng)求,并將該緩存行變成無效(Invalid)。 |
I 無效 (Invalid) | 該Cache line無效。 | 無 |
注意:
對(duì)于M和E狀態(tài)而言總是精確的,他們?cè)诤驮摼彺嫘械恼嬲隣顟B(tài)是一致的,而S狀態(tài)可能是非一致的。如果一個(gè)緩存將處于S狀態(tài)的緩存行作廢了,而另一個(gè)緩存實(shí)際上可能已經(jīng)獨(dú)享了該緩存行,但是該緩存卻不會(huì)將該緩存行升遷為E狀態(tài),這是因?yàn)槠渌彺娌粫?huì)廣播他們作廢掉該緩存行的通知,同樣由于緩存并沒有保存該緩存行的copy的數(shù)量,因此(即使有這種通知)也沒有辦法確定自己是否已經(jīng)獨(dú)享了該緩存行。
從上面的意義看來E狀態(tài)是一種投機(jī)性的優(yōu)化:如果一個(gè)CPU想修改一個(gè)處于S狀態(tài)的緩存行,總線事務(wù)需要將所有該緩存行的copy變成invalid狀態(tài),而修改E狀態(tài)的緩存不需要使用總線事務(wù)。
處理器為提高運(yùn)算速度兒做出違背代碼原有順序的優(yōu)化。
在單核處理器時(shí)代處理器的亂序執(zhí)行優(yōu)化不會(huì)影響執(zhí)行結(jié)果。在多核處理中,某個(gè)核心執(zhí)行寫入操作時(shí),將某個(gè)標(biāo)志當(dāng)做寫入完成,進(jìn)行重排優(yōu)化,可能會(huì)先執(zhí)行標(biāo)志指令導(dǎo)致其他核心以為改核心已經(jīng)執(zhí)行完成寫入操作。從而拿到錯(cuò)誤的值。
堆heap
堆是運(yùn)行時(shí)確定的內(nèi)存,由java GC來維護(hù)大小,優(yōu)點(diǎn)是可以動(dòng)態(tài)的確定大小,缺點(diǎn)是運(yùn)行時(shí)動(dòng)態(tài)確定內(nèi)存所以速度相對(duì)棧小一點(diǎn)。對(duì)象存放在堆上。靜態(tài)變量跟隨類一起存放在堆上。
棧stack
棧內(nèi)存的速度相對(duì)堆內(nèi)存更快,僅次于寄存器,缺點(diǎn)是大小必須是編譯期確定的。缺乏一定的靈活性,存放一些基本的數(shù)據(jù)變量(int double。。。)java內(nèi)存要求本地變量(Local Variable),調(diào)用棧必須存放在線程棧(Thead Stack)中。
本地變量可能存放的是對(duì)象的引用。當(dāng)兩個(gè)線程同時(shí)引用一個(gè)對(duì)象時(shí),那么這兩個(gè)線程的本地引用存放的是這個(gè)對(duì)象的私有拷貝。
硬件內(nèi)存模型如圖
硬件內(nèi)存模型和java內(nèi)存模型的對(duì)應(yīng)模型如圖:
java內(nèi)存抽象模型結(jié)構(gòu)
看圖,本地內(nèi)存:本地內(nèi)存是java抽象的概念,涵蓋了緩存,寫緩存區(qū),寄存器,其他硬件和編譯器優(yōu)化。本地內(nèi)存儲(chǔ)存了共享變量的副本,從硬件的角度上講主內(nèi)存就是硬件內(nèi)存,但是為了獲取更好的速度,java可能會(huì)將數(shù)據(jù)存儲(chǔ)在寄存器或者高速緩存區(qū)。如果線程要通信必須要經(jīng)過主內(nèi)存,流程是先在主內(nèi)存中獲取共享變量,存儲(chǔ)在本地內(nèi)存中經(jīng)由進(jìn)程計(jì)算,然后刷新至主內(nèi)存,再經(jīng)由其他線程訪問。
lock和Unlack:作用在主內(nèi)存上只有在Unlock的情況下內(nèi)存才可以被其他線程鎖定。
Read:作用在主內(nèi)存上,把主內(nèi)存中的變量輸送在工作內(nèi)存中。
Load:作用工作內(nèi)存中,把主內(nèi)存中的值放入到工作內(nèi)存副本中。
use:作用于工作內(nèi)存,把數(shù)據(jù)給執(zhí)行引擎。每當(dāng)執(zhí)行器需要使用到變量時(shí)或者執(zhí)行字節(jié)碼指令時(shí)會(huì)執(zhí)行這個(gè)操作。
assign:賦值,在執(zhí)行賦值操作時(shí)執(zhí)行,將執(zhí)行引擎中的值賦值給工作內(nèi)存。
store:存儲(chǔ),把工作內(nèi)存中的值傳遞到主內(nèi)存中。
write:寫入,將工作內(nèi)存中的值寫入到主內(nèi)存中。
下面介紹一下規(guī)則,規(guī)則是用來限制每一步是如何操作的。
不允許read和load、store和write單一出現(xiàn),因?yàn)樗麄兪且粋€(gè)連貫的操作。而且必須是按順序執(zhí)行的。load必須是read之后,write必須是store之后,但是不一定是連續(xù)操作,在他們之間可以插入其他的指令。
不允許線程丟棄assign操作,也就是說執(zhí)行完了之后必須放入工作內(nèi)存中。
不允許線程不經(jīng)過Assign操作直接把數(shù)據(jù)給主內(nèi)存。
一個(gè)新的變量只能在主內(nèi)存中誕生。
一個(gè)變量只允許一個(gè)線程對(duì)其lack操作,但是可以被一個(gè)線程lack多次,lack多次之后只有執(zhí)行相同次數(shù)的unlack才能被解鎖。
如果一個(gè)變量執(zhí)行了lack操作之后將會(huì)清楚工作內(nèi)存中該變量的值。執(zhí)行引擎在使用變量時(shí)需要重新執(zhí)行read-load-use等操作。
如果沒有執(zhí)行一個(gè)lack操作的變量不能執(zhí)行unlack操作?;蛘弑黄渌€程執(zhí)行了lack操作的線程也不能被改線程執(zhí)行unlack。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/73328.html
摘要:在這個(gè)范圍廣大的并發(fā)技術(shù)領(lǐng)域當(dāng)中多線程編程可以說是基礎(chǔ)和核心,大多數(shù)抽象并發(fā)問題的構(gòu)思與解決都是基于多線程模型來進(jìn)行的。一般來說,多線程程序會(huì)面臨三類問題正確性問題效率問題死鎖問題。 多線程編程或者說范圍更大的并發(fā)編程是一種非常復(fù)雜且容易出錯(cuò)的編程方式,但是我們?yōu)槭裁催€要冒著風(fēng)險(xiǎn)艱辛地學(xué)習(xí)各種多線程編程技術(shù)、解決各種并發(fā)問題呢? 因?yàn)椴l(fā)是整個(gè)分布式集群的基礎(chǔ),通過分布式集群不僅可以大...
摘要:系統(tǒng)級(jí)線程核心級(jí)線程由操作系統(tǒng)內(nèi)核進(jìn)行管理。值得注意的是多線程的存在,不是提高程序的執(zhí)行速度。實(shí)現(xiàn)多線程上面說了一大堆基礎(chǔ),理解完的話。虛擬機(jī)的啟動(dòng)是單線程的還是多線程的是多線程的。 前言 之前花了一個(gè)星期回顧了Java集合: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹介紹 HashMap就是這么簡(jiǎn)單【源碼剖析】 LinkedHashMa...
摘要:本文重點(diǎn)掌握異步編程的相關(guān)概念了解期物的概念意義和使用方法了解中的阻塞型函數(shù)釋放的特點(diǎn)。一異步編程相關(guān)概念阻塞程序未得到所需計(jì)算資源時(shí)被掛起的狀態(tài)。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之控制流程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、掌握異步編程的相關(guān)概念;2、了解期物future的概念、意義和使用方法;3、了解Python...
摘要:程序執(zhí)行時(shí),至少會(huì)有一個(gè)線程在運(yùn)行,這個(gè)運(yùn)行的線程被稱為主線程。程序的終止是指除守護(hù)線程以外的線程全部終止。多線程程序由多個(gè)線程組成的程序稱為多線程程序。線程休眠期間可以被中斷,中斷將會(huì)拋出異常。 線程 我們?cè)陂喿x程序時(shí),表面看來是在跟蹤程序的處理流程,實(shí)際上跟蹤的是線程的執(zhí)行。 單線程程序 在單線程程序中,在某個(gè)時(shí)間點(diǎn)執(zhí)行的處理只有一個(gè)。 Java 程序執(zhí)行時(shí),至少會(huì)有一個(gè)線程在運(yùn)行...
閱讀 743·2023-04-26 02:58
閱讀 2475·2021-09-27 14:01
閱讀 3769·2021-09-22 15:57
閱讀 1351·2019-08-30 15:56
閱讀 1178·2019-08-30 15:53
閱讀 960·2019-08-30 15:52
閱讀 870·2019-08-26 14:01
閱讀 2309·2019-08-26 13:41