欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java并發(fā)編程之Java內(nèi)存模型

 更新時間:2021年11月22日 16:18:03   作者:smileNicky  
這篇文章主要為大家介紹了Java內(nèi)存模型,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助,希望能夠給你帶來幫助

1、什么是Java的內(nèi)存模型

Java內(nèi)存模型簡稱JMM(Java Memory Model),JMM是和多線程并發(fā)相關(guān)的一組規(guī)范。各個jvm實現(xiàn)都要遵循這個JMM規(guī)范。才能保證Java代碼在不同虛擬機順利運行。因此,JMM 與處理器、緩存、并發(fā)、編譯器有關(guān)。它解決了CPU 多級緩存、處理器優(yōu)化、指令重排等導致的結(jié)果不可預期的問題。

在這里插入圖片描述

2、為什么需要Java內(nèi)存模型

程序的運行結(jié)果依賴于處理器,而不同的處理器規(guī)則都不一樣,不同處理器差異是很大的,所以同段代碼在處理器A運行正常,搬到處理器B運行結(jié)果是不一樣的,所以為了兼容這種差異,推出了Java內(nèi)存模型規(guī)范,JMM是一個規(guī)范標準,JMM保證了不同處理器的處理結(jié)果一致,同時也保證不同編譯器、jvm等等的一致性。所以就保證了Java語言“書寫一次、到處運行”

3、Java內(nèi)存模型及操作規(guī)范

1.共享變量都是放在主內(nèi)存中的

2.每個線程都有自己的工作內(nèi)存,線程只可操作自己的工作內(nèi)存

3.線程要操作共享變量,需要從主內(nèi)存中讀取到工作內(nèi)存,改變值之后要從工作內(nèi)存同步到主內(nèi)存

在這里插入圖片描述

4、Java內(nèi)存模型規(guī)定的原子操作

Java內(nèi)存模型的同步交換協(xié)議,規(guī)定了8種原子操作

原子操作:不可被中斷的一個或一系列操作

  • lock(鎖定):將主內(nèi)存中的變量鎖定,為一個線程所獨占
  • unlock(解鎖):將lock加的鎖解除,其他的線程有機會訪問此變量
  • read(讀?。鹤饔糜谥鲀?nèi)存變量,將主內(nèi)存中的變量值讀取到工作內(nèi)存
  • load(加載):作用于工作內(nèi)存,將read讀取到的值保存到工作內(nèi)存中的變量副本
  • use(使用):作用于工作內(nèi)存變量,將值傳遞給線程的代碼執(zhí)行引擎
  • assign(賦值):作用于工作內(nèi)存變量,將執(zhí)行引擎處理返回的值重新賦值給變量副本
  • store(存儲):作用于工作內(nèi)存變量,將變量副本的值傳送到主內(nèi)存中
  • write(寫入):作用于主內(nèi)存變量,將store傳送過來的值寫入到主內(nèi)存的共享變量中

Java內(nèi)存模型的同步交互協(xié)議,執(zhí)行上述8種原子操作時必須滿足如下規(guī)則

不允許read和load,store和write操作之一單獨出現(xiàn)。即不允許加載或同步工作到一半。

不允許一個線程丟棄它最近的assign操作,即變量在工作內(nèi)存中改變之后,必須將數(shù)據(jù)同步回主內(nèi)存

不允許一個線程無原因地(無assign操作)將數(shù)據(jù)從工作內(nèi)存同步到主內(nèi)存中。

一個新的變量可能在主內(nèi)存中誕生。

一個變量在同一個時刻只允許一條線程對其進行l(wèi)ock操作,但lock操作可以被同一條線程重復執(zhí)行多次,多次lock之后必須要執(zhí)行相同次數(shù)unlock操作,變量才會解鎖

如果對一個對象進行l(wèi)ock操作,那么會清空工作內(nèi)存變量中的值,在執(zhí)行引擎使用這個變量前,需要重新執(zhí)行l(wèi)oad或assign操作初始變量的值

如果一個對象事先沒有被lock,就不允許對其進行unlock操作,也不允許去unlock一個被其他線程鎖住的變量。

對一個變量執(zhí)行unlock操作之前,必須將此變量同步回主內(nèi)存中(執(zhí)行store、write)

5、Java內(nèi)存模型同步協(xié)議

Java內(nèi)存模型的同步協(xié)議,操作規(guī)范 將一個變量從主內(nèi)存復制到工作內(nèi)存要順序執(zhí)行read、load操作;要將變量從工作內(nèi)存同步回主內(nèi)存要用store、write操作。只要求順序執(zhí)行,不一定是連續(xù)執(zhí)行

圖引用網(wǎng)上資料:

在這里插入圖片描述

6、Java內(nèi)存模型的HB法則

并發(fā)編程有三個重要特效:原子行可見性、有序性

  • 原子性:原子性是指一個或者多個操作,要么全部執(zhí)行且執(zhí)行過程不會被其它操作打斷,要么全部不執(zhí)行。
  • 可見性:可見性是指共享變量對于多個線程都是可見的,也即一個線程修改了變量,其它線程馬上就能知道
  • 有序性:有序性是指程序的執(zhí)行順序按照代碼的先后順便執(zhí)行

在說JMM的happens-before(HB)法則之前,先說說并發(fā)編程的有序性。說到并發(fā)線程的有序性,還需要涉及到指令重排序

  • 什么是指令重排?

假如我們寫一個程序,我們會期待這些語句的實際執(zhí)行順便和代碼的順序是一致的,大部分情況是一致的,但實際上,編譯器、JVM 或者 CPU 都有可能出于優(yōu)化等目的,對執(zhí)行的順序進行調(diào)整,這個就是指令重排序

  • 重排序的好處:提高處理速度

代碼順序如圖:

在這里插入圖片描述

指令重排后,a=100; a= a+100會提到一起執(zhí)行,效率提高

在這里插入圖片描述

上面的例子,是可以提高執(zhí)行效率,但是有時候指令重排是會導致問題的,如下代碼例子,代碼順序是先初始化content,然后設(shè)置標識為true,線程B檢測到為true之后,調(diào)用content的方法

在這里插入圖片描述

如果指令重排后,這種情況就會出現(xiàn)沒初始化完成,就直接調(diào)用conten的方法

在這里插入圖片描述

所以,指令重排有好處也有壞處,一般可能是cpu、編譯器或者是內(nèi)存會進行指令重排,為了避免指令重排,保證并發(fā)編程的有序性,有時候需要使用synchronized等鎖或者volatile等等方式避免

1.JMM規(guī)定了happens-before(先行發(fā)生)原則,來保證很多操作的有序性。

2.當我們代碼操作不滿足先行發(fā)生原則時,則需在編碼時使用volatile、synchronized來保證有序性

JMM的HB法則

  • 程序順序規(guī)則:每個線程的每個操作都happens-before該線程中任意的后續(xù)操作
  • 監(jiān)視器鎖規(guī)則:一個鎖的解除,happens-before于隨后對這個鎖的加鎖
  • volatile變量規(guī)則:對volatile域的寫,happens-before于任意后續(xù)對這個volatile域的讀
  • 線程啟動規(guī)則:在某個線程對象上調(diào)用start()方法happens-before被啟動線程中的任意動作
  • 線程終止規(guī)則:線程中所有操作都先行發(fā)生于對此線程的終止檢測,如在線程t1中成功執(zhí)行了t2.join(),則t2中的所有操作對t2可見
  • 線程中斷規(guī)則:對線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生
  • 對象終結(jié)規(guī)則:一個對象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行發(fā)生于它的finalize方法的開始傳
  • 遞性:如果A happens-before于B,且B happens-before 于C,那么A happens-before于C

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

最新評論