国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

三道java新手入門面試題,通往自由的道路--JVM

瀏覽:4日期:2022-08-10 16:26:40
目錄1. 你知道JVM內(nèi)存模型嗎?2. 你知道重排序是什么嗎?3. happens-before是什么,和as-if-serial有什么區(qū)別總結(jié)1. 你知道JVM內(nèi)存模型嗎?

在Java的并發(fā)中采用的就是JVM內(nèi)存共享模型即JMM(Java Memory Model),它其實(shí)是是JVM規(guī)范中所定義的一種內(nèi)存模型,跟計(jì)算機(jī)的CPU緩存內(nèi)存模型類似,是基于CPU緩存內(nèi)存模型來(lái)建立的,Java內(nèi)存模型是標(biāo)準(zhǔn)化的,屏蔽掉了底層不同計(jì)算機(jī)的區(qū)別。

那我們先來(lái)講下計(jì)算機(jī)的內(nèi)存模型:

其實(shí)早期計(jì)算機(jī)中CPU和內(nèi)存的速度是差不多的,但在現(xiàn)代計(jì)算機(jī)中,CPU的指令速度遠(yuǎn)超內(nèi)存的存取速度,由于計(jì)算機(jī)的存儲(chǔ)設(shè)備與處理器的運(yùn)算速度有幾個(gè)數(shù)量級(jí)的差距,所以現(xiàn)代計(jì)算機(jī)系統(tǒng)都不得不加入一層讀寫速度盡可能接近處理器運(yùn)算速度的高速緩存(Cache)來(lái)作為內(nèi)存與處理器之間的緩沖。

將運(yùn)算需要使用到的數(shù)據(jù)復(fù)制到緩存中,讓運(yùn)算能快速進(jìn)行,當(dāng)運(yùn)算結(jié)束后再?gòu)木彺嫱交貎?nèi)存之中,這樣處理器就無(wú)須等待緩慢的內(nèi)存讀寫了。

基于高速緩存的存儲(chǔ)交互很好地解決了處理器與內(nèi)存的速度矛盾,但是也為計(jì)算機(jī)系統(tǒng)帶來(lái)更高的復(fù)雜度,因?yàn)樗肓艘粋€(gè)新的問(wèn)題:緩存一致性(CacheCoherence)。

在多處理器系統(tǒng)中,每個(gè)處理器都有自己的高速緩存,而它們又共享同一主內(nèi)存(MainMemory)。

三道java新手入門面試題,通往自由的道路--JVM

而我們可以打開任務(wù)管理器,可以進(jìn)入性能 --> CPU中可以看到L1緩存、L2緩存和L3緩存。

三道java新手入門面試題,通往自由的道路--JVM

可以看到我們CPU跟我們計(jì)算機(jī)之間交互的高速緩存。一般的流程,就是計(jì)算機(jī)會(huì)先從硬盤從讀取數(shù)據(jù)到主內(nèi)存中,又會(huì)從主內(nèi)存讀取數(shù)據(jù)到高速緩存中,而CPU讀取的數(shù)據(jù)就是高速緩存中的數(shù)。

我們現(xiàn)在再來(lái)看看JMM:

JMM是定義了線程和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存在主內(nèi)存(MainMemory)中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存(LocalMemory)即共享變量副本,本地內(nèi)存中存儲(chǔ)了該線程以讀、寫共享變量的副本。本地內(nèi)存是Java內(nèi)存模型的一個(gè)抽象概念,并不真實(shí)存在。它涵蓋了緩存、寫緩沖區(qū)、寄存器等。

JMM模型圖:

三道java新手入門面試題,通往自由的道路--JVM

我們可以發(fā)現(xiàn)在JMM模型中:

所有的共享變量都存在主內(nèi)存中。 每個(gè)線程都保存了一份該線程使用到的共享變量的副本。 線程A是無(wú)法直接訪問(wèn)到線程B的本地內(nèi)存的,只能訪問(wèn)主內(nèi)存。線 程對(duì)共享變量的所有操作都必須在自己的本地內(nèi)存中進(jìn)行,不能直接從主內(nèi)存中讀取。 并發(fā)的三要素:可見性、原子性、有序性,而JMM就主要體現(xiàn)在這三方面。

注意 :因?yàn)榫€程之間無(wú)法相互訪問(wèn),而一旦某個(gè)線程將共享變量進(jìn)行修改,而線程B是無(wú)法發(fā)現(xiàn)到這個(gè)更新值的,所以可能會(huì)出現(xiàn)可見性問(wèn)題。而這里的可見性問(wèn)題就是一個(gè)線程對(duì)共享變量的修改,另一個(gè)線程能夠立刻看到,但此時(shí)無(wú)法看到更新后的內(nèi)存,因?yàn)樵L問(wèn)的是自己的共享變量副本。

解決方案有

加鎖,加synchronized、Lock,保存一個(gè)線程只能等另一個(gè)線程結(jié)束后才能再訪問(wèn)變量。 對(duì)共享變量加上volatile關(guān)鍵字,保證了這個(gè)變量是可見的。2. 你知道重排序是什么嗎?

重排序是指計(jì)算機(jī)在執(zhí)行程序時(shí),為了提高性能,編譯器和處理器常常會(huì)對(duì)指令做重排。

首先我們來(lái)看看為什么指令重排序可以提高性能?

每一個(gè)指令都會(huì)包含多個(gè)步驟,每個(gè)步驟可能使用不同的硬件,而現(xiàn)代處理器會(huì)設(shè)計(jì)為一個(gè)時(shí)鐘周期完成一條執(zhí)行時(shí)間最長(zhǎng)的指令,為什么會(huì)這樣呢?

主要原理就是可以指令1還沒(méi)有執(zhí)行完,就可以開始執(zhí)行指令2,而不用等到指令1執(zhí)行結(jié)束之后再執(zhí)行指令2,這樣就大大提高了效率。

例如:每條指令拆分為五個(gè)階段:

三道java新手入門面試題,通往自由的道路--JVM

想這樣如果是按順序串行執(zhí)行指令,那可能相對(duì)比較慢,因?yàn)樾枰却弦粭l指令完成后,才能等待下一步執(zhí)行:

三道java新手入門面試題,通往自由的道路--JVM

而如果發(fā)生指令重排序呢,實(shí)際上雖然不能縮短單條指令的執(zhí)行時(shí)間,但是它變相地提高了指令的吞吐量,可以在一個(gè)時(shí)鐘周期內(nèi)同時(shí)運(yùn)行五條指令的不同階段。

三道java新手入門面試題,通往自由的道路--JVM

我們來(lái)分析下代碼的執(zhí)行情況,并思考下:

a = b + c;

d = e - f ;

按原先的思路,會(huì)先加載b和c,再進(jìn)行b+c操作賦值給a,接下來(lái)就會(huì)加載e和f,最后就是進(jìn)行e-f操作賦值給d。

這里有什么優(yōu)化的空間呢?我們?cè)趫?zhí)行b+c操作賦值給a時(shí),可能需要等待b和c加載結(jié)束,才能再進(jìn)行一個(gè)求和操作,所以這里可能出現(xiàn)了一個(gè)停頓等待時(shí)間,依次后面的代碼也可能會(huì)出現(xiàn)停頓等待時(shí)間,這降低了計(jì)算機(jī)的執(zhí)行效率。

為了去減少這個(gè)停頓等待時(shí)間,我們可以先加載e和f,然后再去b+c操作賦值給a,這樣做對(duì)程序(串行)是沒(méi)有影響的,但卻減少了停頓等待時(shí)間。既然b+c操作賦值給a需要停頓等待時(shí)間,那還不如去做一些有意義的事情。

總結(jié):指令重排對(duì)于提高CPU處理性能十分必要。雖然由此帶來(lái)了亂序的問(wèn)題,但是這點(diǎn)犧牲是值得的。

重排序的類型有以下幾種:

三道java新手入門面試題,通往自由的道路--JVM

指令重排一般分為以下三種:

編譯器優(yōu)化重排

編譯器在不改變單線程程序語(yǔ)義的前提下,可以重新安排語(yǔ)句的執(zhí)行順序。

指令并行重排

現(xiàn)代處理器采用了指令級(jí)并行技術(shù)來(lái)將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴性(即后一個(gè)執(zhí)行的語(yǔ)句無(wú)需依賴前面執(zhí)行的語(yǔ)句的結(jié)果),處理器可以改變語(yǔ)句對(duì)應(yīng)的機(jī)器指令的執(zhí)行順序。

內(nèi)存系統(tǒng)重排

由于處理器使用緩存和讀寫緩存沖區(qū),這使得加載(load)和存儲(chǔ)(store)操作看上去可能是在亂序執(zhí)行,因?yàn)槿?jí)緩存的存在,導(dǎo)致內(nèi)存與緩存的數(shù)據(jù)同步存在時(shí)間差。

而在重排序中還需要一個(gè)概念的東西:as-if-serial

不管如何重排序,都必須保證代碼在單線程下的運(yùn)行正確,連單線程下都無(wú)法正確,更不用討論多線程并發(fā)的情況,所以就提出了一個(gè)as-if-serial的概念。

as-if-serial語(yǔ)義的意思是:

不管怎么重排序,程序的執(zhí)行結(jié)果不能被改變。編譯器、runtime和處理器都必須遵守as-if-serial語(yǔ)義。 為了遵守as-if-serial語(yǔ)義,編譯器和處理器不會(huì)對(duì)存在數(shù)據(jù)依賴關(guān)系的操作做重排序,因?yàn)檫@種重排序會(huì)改變執(zhí)行結(jié)果。(強(qiáng)調(diào)一下,這里所說(shuō)的數(shù)據(jù)依賴性僅針對(duì)單個(gè)處理器中執(zhí)行的指令序列和單個(gè)線程中執(zhí)行的操作,不同處理器之間和不同線程之間的數(shù)據(jù)依賴性不被編譯器和處理器考慮)。但是,如果操作之間不存在數(shù)據(jù)依賴關(guān)系,這些操作依然可能被編譯器和處理器重排序。3. happens-before是什么,和as-if-serial有什么區(qū)別

happens-before的概念:

一方面,程序員需要JMM提供一個(gè)強(qiáng)的內(nèi)存模型來(lái)編寫代碼;另一方面,編譯器和處理器希望JMM對(duì)它們的束縛越少越好,這樣它們就可以最可能多的做優(yōu)化來(lái)提高性能,希望的是一個(gè)弱的內(nèi)存模型。

JMM考慮了這兩種需求,并且找到了平衡點(diǎn),對(duì)編譯器和處理器來(lái)說(shuō),只要不改變程序的執(zhí)行結(jié)果(單線程程序和正確同步了的多線程程序),編譯器和處理器怎么優(yōu)化都行。

而對(duì)于程序員,JMM提供了happens-before規(guī)則(JSR-133規(guī)范),在JMM中,如果一個(gè)線程執(zhí)行的結(jié)果需要對(duì)另一個(gè)操作進(jìn)行可見,那么這兩個(gè)操作直接必須存在happens-before關(guān)系。

JMM使用happens-before的概念來(lái)定制兩個(gè)操作之間的執(zhí)行順序。這并不意味著前一個(gè)操作必須要在后一個(gè)操作之前執(zhí)行!happens-before僅僅要求前一個(gè)操作(執(zhí)行的結(jié)果)對(duì)后一個(gè)操作可見,且前一個(gè)操作按順序排在第二個(gè)操作之前 。

happens-before關(guān)系的定義如下:

如果一個(gè)操作happens-before另一個(gè)操作,那么第一個(gè)操作的執(zhí)行結(jié)果將對(duì)第二個(gè)操作可見,而且第一個(gè)操作的執(zhí)行順序排在第二個(gè)操作之前。 兩個(gè)操作之間存在happens-before關(guān)系,并不意味著Java平臺(tái)的具體實(shí)現(xiàn)必須要按照happens-before關(guān)系指定的順序來(lái)執(zhí)行。如果重排序之后的執(zhí)行結(jié)果,與按happens-before關(guān)系來(lái)執(zhí)行的結(jié)果一致,那么JMM也允許這樣的重排序。 happens-before關(guān)系保證正確同步的多線程程序的執(zhí)行結(jié)果不被重排序改變。

在Java中,有以下天然的Happens-Before規(guī)則:

程序順序規(guī)則:一個(gè)線程中的每一個(gè)操作,happens-before于該線程中的任意后續(xù)操作。 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖,happens-before于隨后對(duì)這個(gè)鎖的加鎖。 volatile變量規(guī)則:對(duì)一個(gè)volatile域的寫,happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀。 傳遞性:如果A happens-before B,且B happens-before C,那么A happens-before C。 start規(guī)則:如果線程A執(zhí)行操作ThreadB.start()啟動(dòng)線程B,那么A線程的ThreadB.start()操作happens-before于線程B中的任意操作、 join規(guī)則:如果線程A執(zhí)行操作ThreadB.join()并成功返回,那么線程B中的任意操作happens-before于線程A從ThreadB.join()操作成功返回。 線程中斷規(guī)則:對(duì)線程interrupt()方法的調(diào)用happens-before于被中斷線程的代碼檢測(cè)到中斷事件的發(fā)生。

Happens-Before和as-if-serial的關(guān)系實(shí)質(zhì)上是一回事。

as-if-serial語(yǔ)義保證單線程內(nèi)重排序后的執(zhí)行結(jié)果和程序代碼本身應(yīng)有的結(jié)果是一致的,happens-before關(guān)系保證正確同步的多線程程序的執(zhí)行結(jié)果不被重排序改變。 as-if-serial語(yǔ)義和happens-before這么做的目的,都是為了在不改變程序執(zhí)行結(jié)果的前提下,盡可能地提高程序執(zhí)行的并行度。總結(jié)

這篇文章就到這里了,如果這篇文章對(duì)你也有所幫助,希望您能多多關(guān)注好吧啦網(wǎng)的更多內(nèi)容!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 中文字幕亚洲视频 | 搞黄网站免费看 | 国产手机在线国内精品 | 一级做a爰性色毛片 | 男女性高清爱潮视频免费观看 | 亚洲综合影视 | 免费观看成年的网站 | 国产一区二区三区不卡在线观看 | 成人午夜在线视频 | 18在线| 日本欧美一级二级三级不卡 | 久久综合久久自在自线精品自 | 中文字幕免费观看 | 米奇久久 | 国产成人综合亚洲 | 久草在线最新 | 国内成人免费视频 | 亚洲欧美一区二区三区孕妇 | 精品国产亚洲人成在线 | 香蕉亚洲精品一区二区 | 久久无码精品一区二区三区 | 深夜福利网站在线观看 | 国产偷国产偷亚洲高清在线 | 久久思| 中文字幕一区二区精品区 | 欧美一级毛片欧美一级成人毛片 | 爱久久精品国产 | 91久久国产综合精品女同我 | 欧美成人精品一区二区 | 成人亚洲欧美日韩在线 | 九九精品视频在线播放 | 亚洲欧美日韩国产专区一区 | 国产精品二 | 性感美女视频黄.免费网站 性高湖久久久久久久久 | 精品一久久香蕉国产线看观 | 欧美在线一级毛片观看 | 日本精品一区二区三区在线 | 看毛片的网址 | 国产成人高清精品免费观看 | 热99re久久国超精品首页 | 午夜两性试爱视频免费 |