日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 并发模型总类_java并发编程系列-内存模型基础

發(fā)布時間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 并发模型总类_java并发编程系列-内存模型基础 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java線程之間的通信對程序開發(fā)人員是完全透明的,內(nèi)存的可見性問題很容易困擾很多開發(fā)人員。本篇博文將揭開java內(nèi)存模型的神秘面紗,來看看內(nèi)存模型到底是怎樣的。

并發(fā)編程模型的分類

并發(fā)編程中需要處理的兩個關(guān)鍵問題:線程之間如何通信

線程之間如何同步

所謂通信是指線程之間以何種機制來交換信息,在命令式編程中,線程的通信機制有兩種:共享內(nèi)存(隱式通信:通過共享程序的公共狀態(tài),讀-寫內(nèi)存中的公共狀態(tài)實現(xiàn))

消息傳遞(顯示通信:線程間發(fā)送消息實現(xiàn) ,比較典型的就是wait()和notify())

所謂同步,就是控制不同線程間操作發(fā)生相對順序的機制:共享內(nèi)存(同步是顯示的,由程序開發(fā)人員顯示的指定某段代碼或者某個方法需要在線程之間互斥執(zhí)行)。

消息傳遞(同步是隱式的,消息的發(fā)送必須在消息接收之前)。

java的并發(fā)采用的是共享內(nèi)存模型,線程之間的通信是隱式執(zhí)行的,同步需要開發(fā)人員顯示進行控制。

JAVA內(nèi)存模型(JMM)的抽象

JMM把java虛擬機內(nèi)部劃分為線程棧和堆。邏輯視圖如下:

JMM邏輯視圖.png

java中所有的實例域、靜態(tài)域,數(shù)組元素都是存儲在堆內(nèi)存,堆內(nèi)存在線程之間共享。而對象引用,局部變量、方法參數(shù)和異常處理器參數(shù)都是存在在棧內(nèi)存,也就是線程棧中,線程棧中的變量僅對自己可見,對其他線程不可見。不同線程之間的通信由java內(nèi)存模型(java memory model ,簡稱JMM)控制。JMM的抽象結(jié)構(gòu)圖,如下:

JMM內(nèi)存模型抽象圖.png

線程之間的共享變量存儲在堆內(nèi)存,每個線程都有私有的本地內(nèi)存(線程棧),私有本地內(nèi)存中存儲了主內(nèi)存中共享變量的拷貝,本地內(nèi)存只是JMM的一個抽象概念,并不真實存在。

上圖中線程A要與線程B通信的話,由于線程本地變量的不可見性,首先要將線程A中變量的更改,刷新到主內(nèi)存中,然后線程B本地私有的共享變量副本失效,從新讀取刷新的新值,才能完成。從上面的描述看,線程A向線程B通信,必須要經(jīng)過主內(nèi)存,JMM控制主內(nèi)存與每個線程的本地變量的交互,來為java程序員提供內(nèi)存的可見性。

硬件內(nèi)存架構(gòu)

軟件最終還要運行在硬件上,看一下現(xiàn)代計算機硬件內(nèi)存架構(gòu)的簡單圖示:

硬件模型.png

現(xiàn)在的計算機一般都有兩個或者多個CPU,其中有些還是多核心實現(xiàn)。

每個CPU都包含一系列的寄存器,它們是CPU內(nèi)內(nèi)存的基礎(chǔ)。CPU在寄存器上執(zhí)行操作的速度遠大于在主存上執(zhí)行的速度。這是因為CPU訪問寄存器的速度遠大于主存。

每個CPU可能還有一個CPU緩存層。實際上,絕大多數(shù)的現(xiàn)代CPU都有一定大小的緩存層。CPU訪問緩存層的速度快于訪問主存的速度,但通常比訪問內(nèi)部寄存器的速度還要慢一點。一些CPU還有多層緩存,但這些對理解Java內(nèi)存模型如何和內(nèi)存交互不是那么重要。只要知道CPU中可以有一個緩存層就可以了。

一個計算機還包含一個主存。所有的CPU都可以訪問主存。主存通常比CPU中的緩存大得多。

CPU的高速緩存雖然解決了效率的問題,但是又帶來了一個新的問題:數(shù)據(jù)一致性。當(dāng)一個CPU需要讀取主存時,它會將主存的部分讀到CPU緩存中。它甚至可能將緩存中的部分內(nèi)容讀到它的內(nèi)部寄存器中,然后在寄存器中執(zhí)行操作,這樣就不會使CPU直接與內(nèi)存相連。當(dāng)CPU需要將結(jié)果寫回到主存中去時,它會將內(nèi)部寄存器的值刷新到緩存中,然后在某個時間點將值刷新回主存。

Java內(nèi)存模型和硬件內(nèi)存架構(gòu)之間的橋接

上面已經(jīng)提到,Java內(nèi)存模型與硬件內(nèi)存架構(gòu)之間存在差異。硬件內(nèi)存架構(gòu)沒有區(qū)分線程棧和堆。對于硬件,所有的線程棧和堆都分布在主內(nèi)中。部分線程棧和堆可能有時候會出現(xiàn)在CPU緩存中和CPU內(nèi)部的寄存器中。如下圖所示:

image.png

Java內(nèi)存模型的基礎(chǔ)原理

從源代碼到指令序列的重排序

在程序執(zhí)行時,為了提高程序的執(zhí)行性能,編譯器和處理器常常會對指令做重排序,換句話說程序的執(zhí)行順序和程序開發(fā)人員編寫的順序可能會存在差異,這是編譯器和處理器對源代碼做了優(yōu)化。但是JMM的編譯器重排序規(guī)則會禁止特定類型的編譯器重排序,對于處理器的重排序,JMM的處理器重排序規(guī)則會要求java編譯器在生成指令時,插入特定的內(nèi)存屏障(Memory Barriers)指令,來禁止特定類型的處理器重排序。換句話說編譯器和處理器的重排序都是可控的。

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

指令級重排序:現(xiàn)在的處理器都采用了并行技術(shù),可以將多條執(zhí)行重疊執(zhí)行,如果不存在數(shù)據(jù)依賴性,可以改變語句對應(yīng)機器語句的執(zhí)行順序。之所以存在數(shù)據(jù)依賴的語句不做重排序是因為改變順序后將導(dǎo)致執(zhí)行結(jié)果發(fā)生變化。

內(nèi)存系統(tǒng)重排序:由于處理器使用緩存和讀/寫緩沖區(qū),這使得加載和存儲操作看上去可能是在亂序執(zhí)行。

JMM屬于語言級的內(nèi)存模型,它確保在不同的編譯器和不同的處理器平臺上,通過禁止特定類型的編譯器和處理器重排序,為程序員提供一致性的內(nèi)存可見性保證。

重排序與內(nèi)存屏障

為了保證內(nèi)存可見性,Java編譯器在生成指令序列的適當(dāng)位置會插入內(nèi)存屏障指令來禁止特定類型的處理器重排序。內(nèi)存屏障又稱為內(nèi)存柵欄,是一個CPU指令:保證特定的操作順序

影響某些數(shù)據(jù)的內(nèi)存可見性

例如: volatile關(guān)鍵字 就是通過內(nèi)存屏障實現(xiàn)的。

happens-before

JSP-133(內(nèi)存模型)使用happens-before來闡述操作之間的內(nèi)存可見性。在JMM中如果一個操作執(zhí)行結(jié)果需要對另一個操作可見,那么這兩個操作之間必須要存在happens-before關(guān)系。兩個操作具有happens-before關(guān)系,并不意味著前一個操作必須要在后一個操作之間執(zhí)行,happens-before僅僅要求前一個操作的執(zhí)行結(jié)果對后一個操作可見。且前一個操作按順序排在第二個操作的前面。

happens-before規(guī)則如下:程序順序規(guī)則:一個線程中的每個操作,happens-before于線程中任意后續(xù)操作

監(jiān)視器鎖規(guī)則:對一個鎖的解鎖,happens-before于隨后對這個鎖的加鎖

volatil變量規(guī)則:對一個volatile域的寫,happens-before與任意后續(xù)對這個volatile域的讀

傳遞性:如果A happens-before B ,且B happens-before C , 那么A happens-before C .

重排序

數(shù)據(jù)依賴

如果兩個操作訪問同一個變量,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在數(shù)據(jù)的依賴性。寫后讀 a=1;b=a

寫后寫 a=1 ; a =2

讀后寫 a=b ; b =1

上面三種情況,只要重排序兩個操作的執(zhí)行順序,程序的執(zhí)行結(jié)果就會發(fā)生改變。編譯器和處理器可能會對操作做重排序。做重排序時,會遵守數(shù)據(jù)依賴性,編譯器和處理器不會改變存在數(shù)據(jù)依賴關(guān)系的兩個操作的執(zhí)行順序,只針對單個處理器和單個線程而言。

as-if-serial語義

它的意思是不管怎么重排序,單線程執(zhí)行的結(jié)果都不會發(fā)生變化。為了遵守as-if-serial語義,編譯器和處理器都不會對存在數(shù)據(jù)依賴的語句執(zhí)行重排序。

順序一致性

數(shù)據(jù)競爭與順序一致性保證

當(dāng)程序未正確同步時,就可能存在數(shù)據(jù)競爭。在一個線程中寫一個變量

在另一個線程中讀同一個變量

而且讀寫沒有通過同步來排序

順序一致性內(nèi)存模型

兩大特性:一個線程中所有操作必須按照程序的順序來執(zhí)行

所有線程都只能看到一個單一的操作執(zhí)行順序。在順序一致性內(nèi)存模型中,每個操作都必須原子執(zhí)行且立刻對所有線程可見。

同步程序的順序一致性效果

同步程序的順序一致性效果將于程序在順序一致性模型中的執(zhí)行結(jié)果相同。

未同步程序的執(zhí)行特性

對于未同步或未正確同步的多線程程序,JMM只提供最小安全性。JMM不保證未同步的程序的執(zhí)行結(jié)果與該程序在順序一致性模型中的執(zhí)行結(jié)果一致。

作者:起個名忒難

鏈接:https://www.jianshu.com/p/de47a2e49e5d

總結(jié)

以上是生活随笔為你收集整理的java 并发模型总类_java并发编程系列-内存模型基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。