亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2021年11月04日 08:51:52   作者:李子捌  
這篇文章主要介紹了Java并發(fā)編程之內(nèi)存模型,Java內(nèi)存模型中的順序一致性,主要介紹重排序與順序一致性內(nèi)存模型,下面文章將圍繞Java內(nèi)存模型展開(kāi)內(nèi)容,需要的小伙伴可以參考一下

簡(jiǎn)介:

Java線程之間的通信對(duì)程序員完全透明,內(nèi)存可見(jiàn)性問(wèn)題很容易困擾Java程序員,這一系列幾篇文章將揭開(kāi)Java內(nèi)存模型的神秘面紗。

這一系列的文章大致分4個(gè)部分,分別是:

  • Java內(nèi)存模型基礎(chǔ),主要介紹內(nèi)存模型相關(guān)基本概念
  • Java內(nèi)存模型中的順序一致性,主要介紹重排序與順序一致性內(nèi)存模型
  • 同步原語(yǔ),主要介紹三個(gè)同步原語(yǔ)(synchronizedvolatile和final)的內(nèi)存語(yǔ)義及重排序規(guī)則在處理器中的實(shí)現(xiàn)
  • Java內(nèi)存模型的設(shè)計(jì),主要介紹Java內(nèi)存模型的設(shè)計(jì)原理,及其與處理器內(nèi)存模型和順序一致性內(nèi)存模型的關(guān)系。

一、Java內(nèi)存模型的基礎(chǔ)

1.1 并發(fā)編程模型的兩個(gè)關(guān)鍵問(wèn)題

在并發(fā)編程中需要處理兩個(gè)關(guān)鍵問(wèn)題:線程之間如何通信及線程之間如何同步(這里的線程是指并發(fā)執(zhí)行的活動(dòng)實(shí)體)。

通信——線程之間以何種機(jī)制來(lái)交換信息。在命令式編程中,線程之間的通信機(jī)制有兩種:共享內(nèi)存和消息傳遞。

  • 共享內(nèi)存:線程之間共享程序的公共狀態(tài),通過(guò)讀寫(xiě)內(nèi)存中的公共轉(zhuǎn)臺(tái)進(jìn)行隱式通信
  • 消息傳遞:線程之間沒(méi)有公共狀態(tài),線程之間必須通過(guò)發(fā)送消息來(lái)顯式進(jìn)行通信

同步——程序中用于控制不同線程鍵操作發(fā)生相對(duì)順序的機(jī)制。

  • 共享內(nèi)存:同步是顯式進(jìn)行的,由于程序員必須顯式指定某個(gè)方法或某段代碼需要在線程之間互斥執(zhí)行
  • 消息傳遞:同步是隱式進(jìn)行的,由于消息的發(fā)送必須在消息的接收之前。

總結(jié):

Java的并發(fā)采用的是共享內(nèi)存模型,Java線程之間的通信總是隱式進(jìn)行,整個(gè)通信過(guò)程對(duì)程序員完全透明,如果編寫(xiě)多線程程序的Java程序員不理解隱式進(jìn)行線程之間的通信的工作機(jī)制,很可能會(huì)遇到各種奇怪的內(nèi)存可見(jiàn)性問(wèn)題。

1.2 Java內(nèi)存模型的抽象結(jié)構(gòu)

Java中所有的實(shí)例域、靜態(tài)域和數(shù)組元素都存儲(chǔ)在堆內(nèi)存中,堆內(nèi)存在線程之間共享(文章中用“共享變量”指代)。局部變量(Local Variables)、方法定義參數(shù)(Formal Method Parameters)和異常處理器參數(shù)(Exception Handler Parameters)不會(huì)在線程之間共享,它們不會(huì)存在內(nèi)存可見(jiàn)性問(wèn)題,因此也不受內(nèi)存模型的影響。
Java線程之間的通信由Java內(nèi)存模型(JMM)控制,JMM決定一個(gè)線程對(duì)共享變量的寫(xiě)入何時(shí)對(duì)另一個(gè)線程可見(jiàn)。從抽象的角度來(lái)看,JMM定義了線程和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲(chǔ)在主內(nèi)存中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存(Local Memory),本地內(nèi)存中存儲(chǔ)了該線程以讀/寫(xiě)共享變量的副本。本地內(nèi)存時(shí)JMM的一個(gè)抽象概念,并不真實(shí)存在。JMM涵蓋了緩存、寫(xiě)緩沖區(qū)、寄存器以及其他的硬件和編譯器優(yōu)化。

圖示:Java內(nèi)存模型的抽象示意圖

從上圖來(lái)看,線程A和線程B之間要通信的話,必須經(jīng)歷下面2個(gè)步驟。

  • 線程A把本地內(nèi)存A中更新過(guò)的變量刷新到主內(nèi)存中
  • 線程B到主內(nèi)存中去讀取線程A之前已更新過(guò)的共享變量

圖示:線程之間通信示意圖

如上圖所示,本地內(nèi)存A和本地內(nèi)存B有主內(nèi)存中共享變量X的副本。假設(shè)初始時(shí),這三個(gè)內(nèi)存中的X的值都是0.線程A在執(zhí)行時(shí),把更新后的X的值(假設(shè)值為1)臨時(shí)存放在自己的本地內(nèi)存A中。當(dāng)線程A和線程B需要通信是,線程A首先把自己本地內(nèi)存中修改后的X刷新到主內(nèi)存中,此時(shí)主內(nèi)存中的X值變?yōu)榱?.隨后,線程B到主內(nèi)存中去讀取線程A更新后的X值,此時(shí)線程B的本地內(nèi)存X的值也更新成了1。
從整體來(lái)看,這兩個(gè)步驟實(shí)質(zhì)上是線程A在向線程B發(fā)送消息,而且這個(gè)通信過(guò)程必須要經(jīng)過(guò)主內(nèi)存。JMM通過(guò)控制主內(nèi)存與每個(gè)線程的本地內(nèi)存之間的交互,來(lái)為Java程序員提供內(nèi)存可見(jiàn)性保證。

1.3 從源代碼到指令重排序

在執(zhí)行程序時(shí),為了提高性能,編譯器和處理器常常會(huì)對(duì)指令做重排序。重排序分為三種類型:

  • 編譯器優(yōu)化的重排序。編譯器在不改變單線程程序語(yǔ)義的前提下,可以重新安排語(yǔ)句的執(zhí)行順序。
  • 指令級(jí)并行的重排序?,F(xiàn)代處理器采用了指令級(jí)并行技術(shù)(Instruction-Level Parallelism,ILP)來(lái)將對(duì)跳指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴性,處理器可以改變語(yǔ)句對(duì)應(yīng)及其指令的執(zhí)行順序。
  • 內(nèi)存系統(tǒng)的重排序。由于處理器使用緩存和讀/寫(xiě)緩沖區(qū),這使得加載和存儲(chǔ)操作看上去可能是在亂序執(zhí)行。

從Java源代碼的最終實(shí)際執(zhí)行的指令序列,會(huì)分別經(jīng)歷下面3種重排序,其中1屬于編譯器重排序,2和3屬于處理器重排序。

源代碼到最終執(zhí)行的指令序列示意圖:

重排序可能會(huì)導(dǎo)致多線程程序出現(xiàn)內(nèi)存可見(jiàn)性問(wèn)題,對(duì)于編譯器,JMM的編譯器重排序規(guī)則會(huì)禁止特定類型的編譯器重排序(不是所有的編譯器重排序都需要禁止)。對(duì)于處理器重排序,JMM的處理器重排序規(guī)則會(huì)要求Java編譯器在生成指令序列時(shí),插入特定類型的內(nèi)存屏障(Memory Barries, Intel稱之為Memory Fence)指令,通過(guò)內(nèi)存屏障指令來(lái)禁止特定類型的處理器重排序。
JMM屬于語(yǔ)言級(jí)的內(nèi)存模型,它確保在不同的編譯器和不同的處理器平臺(tái)之上,通過(guò)禁止特定類型的編譯器重排序和處理器重排序,為程序員提供一致的內(nèi)存可見(jiàn)性保障。

1.4 寫(xiě)緩沖區(qū)和內(nèi)存屏障

1.4.1 寫(xiě)緩沖區(qū)

現(xiàn)代處理器都會(huì)使用寫(xiě)緩沖區(qū)臨時(shí)保存向內(nèi)存中寫(xiě)入的數(shù)據(jù)。寫(xiě)緩沖區(qū)的主要作用:

  • 可以保證指令流水線持續(xù)運(yùn)行,可以避免由于處理器停頓下來(lái)等待向內(nèi)存寫(xiě)入數(shù)據(jù)而產(chǎn)生的延遲。
  • 它以批處理的方式方式刷新寫(xiě)緩沖區(qū),以及合并寫(xiě)緩沖區(qū)中對(duì)統(tǒng)一地址的多次寫(xiě),減少對(duì)內(nèi)存總線的占用。

常見(jiàn)處理器允許的重排序類型(Y-表示允許兩個(gè)操作重排序,N-表示處理器不允許兩個(gè)操作重排序)

處理器 \規(guī)則 Load-Load Load-Store Store-Store Store-Load 數(shù)據(jù)依賴性
SPARC-TSO N N N Y N
x86 N N N Y N
IA64 Y Y Y Y N
PowerPC Y Y Y Y N
說(shuō)明:常見(jiàn)處理器都允許Store-Load重排序;常見(jiàn)的處理器都不允許對(duì)存在數(shù)據(jù)依賴性的操作做重排序。N多的表示處理器擁有相對(duì)較強(qiáng)的處理器內(nèi)存模型。
由于寫(xiě)緩沖器僅僅只對(duì)它所在的處理器可見(jiàn),這個(gè)特性會(huì)對(duì)內(nèi)存操作的執(zhí)行順序產(chǎn)生非常重要的影響:處理器對(duì)內(nèi)存的讀/寫(xiě)操作的執(zhí)行順序,不一定與內(nèi)存實(shí)際發(fā)生的讀/寫(xiě)操作順序一致。
舉例說(shuō)明:
示例項(xiàng)目 \處理器 Processor A Processor B
偽代碼 a=1; //A1x=b;//A2 b=2;//B1y=a;//B2
可能運(yùn)行結(jié)果 初始狀態(tài):a=b=0;處理器允許執(zhí)行后得到結(jié)果:x=y=0;
假設(shè)處理器A和處理器B按程序的順序并行執(zhí)行內(nèi)存訪問(wèn),最終可能得到x=y=0的結(jié)果,具體原因如下:

處理器和內(nèi)存交互:

說(shuō)明:處理器A和處理器B可以同時(shí)把共享變量寫(xiě)入自己的寫(xiě)緩沖區(qū)(A1、B1),然后從內(nèi)存中讀取另一個(gè)共享變量(A2、B2),最后才把自己寫(xiě)緩沖區(qū)中保存的臟數(shù)據(jù)刷新到內(nèi)存中(A3、B3)。當(dāng)以這種時(shí)序執(zhí)行時(shí),程序就可以得到x=y=0結(jié)果。

1.4.2 內(nèi)存屏障

為了保證內(nèi)存可見(jiàn)性,Java編譯器在生成指令序列的適當(dāng)位置會(huì)插入內(nèi)存屏障指令來(lái)禁止特定類型的處理器重排序。

JMM把內(nèi)存屏障指令分為4類:

屏障類型 指令示例 說(shuō)明
LoadLoad Barriers Load1;LoadLoad;Load2 確保Load1數(shù)據(jù)的裝載先于Load2及所有后續(xù)裝載指令的裝載
StoreStore Barriers Store1;StoreStore;Store2 確保Store1數(shù)據(jù)對(duì)其他處理器可見(jiàn)(刷新到主內(nèi)存)先于Store2及所有后續(xù)存儲(chǔ)指令的存儲(chǔ)
LoadStore Barriers Load1;LoadStore;Store2 確保Load1數(shù)據(jù)裝載先于Store2及后續(xù)的存儲(chǔ)指令刷新到內(nèi)存
StoreLoad Barriers**** Store1;StoreLoad;Load2 確保Store1數(shù)據(jù)對(duì)其他處理器變得可見(jiàn)(指刷新到主內(nèi)存)先于Load2及所有后續(xù)裝載指令的裝載。StoreLoad Barriers會(huì)使該屏障之前的所有內(nèi)存訪問(wèn)指令(存儲(chǔ)和裝載指令)完成之后,才執(zhí)行屏障之后的內(nèi)存訪問(wèn)指令。

StoreLoad Barriers是一個(gè)“全能型屏障”,它同時(shí)具有其它3個(gè)屏障的效果?,F(xiàn)代大多數(shù)處理器支持該屏障(其他類型的屏障不一定被所有處理器支持)。執(zhí)行該屏障開(kāi)銷(xiāo)會(huì)很昂貴,因?yàn)樘幚砥餍枰丫彌_區(qū)的內(nèi)容全部刷新到內(nèi)存中(Buffer Fully Flush)。

1.5 happens-before 簡(jiǎn)介

從JDK1.5開(kāi)始,Java使用新的JSR-133內(nèi)存模型。JSR-133使用happens-before的概念來(lái)闡述操作之間的內(nèi)存可見(jiàn)性。在JMM中,如果一個(gè)操作的結(jié)果需要對(duì)另一個(gè)操作可見(jiàn),那么這兩個(gè)操作之間必須存在happens-before關(guān)系。這里的兩個(gè)操作可以是單線程也可以是多線程。

happens-before規(guī)則:

  • 程序順序規(guī)則:一個(gè)線程中的每個(gè)操作,happens-before于該線程的任意后續(xù)操作。
  • 監(jiān)視器鎖規(guī)則:對(duì)于一個(gè)鎖的解鎖,happens-before于隨后對(duì)這個(gè)鎖的加鎖。
  • volatile變量規(guī)則:對(duì)于一個(gè)volitale域的寫(xiě),happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀。
  • 傳遞性:如果A happens-before B,且B happens-before C ,那么A happens-before C

注意:

兩個(gè)操作之間具有happens-before關(guān)系,并不意味著前一個(gè)操作必須在后一個(gè)操作之前執(zhí)行!happens-before僅僅要求前一個(gè)操作(執(zhí)行的結(jié)果)對(duì)后一個(gè)操作可見(jiàn),且前一個(gè)操作按順序排在第二個(gè)操作之前(the first is visiable to and ordered beofre the second)。

圖示happens-before與JMM的關(guān)系:

一個(gè)happens-before規(guī)則對(duì)應(yīng)于一個(gè)或多個(gè)編譯器個(gè)處理器重排序規(guī)則。對(duì)于Java程序員來(lái)說(shuō),happens-before規(guī)則簡(jiǎn)單易懂,它避免了Java程序員為了理解JMM提供的內(nèi)存可見(jiàn)性保證而去學(xué)習(xí)復(fù)雜的重排序規(guī)則以及這些規(guī)則的具體實(shí)現(xiàn)方法。

到此這篇關(guān)于Java并發(fā)編程之內(nèi)存模型的文章就介紹到這了,更多相關(guān)Java內(nèi)存模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文詳解Spring Security的基本用法

    一文詳解Spring Security的基本用法

    Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問(wèn)控制框架, 提供了完善的認(rèn)證機(jī)制和方法級(jí)的授權(quán)功能。本文將通過(guò)一個(gè)簡(jiǎn)單的案例了解一下Spring Security的基本用法,需要的可以參考一下
    2022-05-05
  • java.security.egd?作用詳解

    java.security.egd?作用詳解

    這篇文章主要為大家介紹了java.security.egd作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • springboot mybatis里localdatetime序列化問(wèn)題的解決

    springboot mybatis里localdatetime序列化問(wèn)題的解決

    這篇文章主要介紹了springboot mybatis里localdatetime序列化問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • java中的空指針異常情況以及解決方案

    java中的空指針異常情況以及解決方案

    這篇文章主要介紹了java中的空指針異常情況以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java多線程工具CompletableFuture的使用教程

    Java多線程工具CompletableFuture的使用教程

    CompletableFuture實(shí)現(xiàn)了CompletionStage接口和Future接口,前者是對(duì)后者的一個(gè)擴(kuò)展,增加了異步回調(diào)、流式處理、多個(gè)Future組合處理的能力。本文就來(lái)詳細(xì)講講CompletableFuture的使用方式,需要的可以參考一下
    2022-08-08
  • SpringBoot中pom.xml配置詳解

    SpringBoot中pom.xml配置詳解

    pom.xml是Maven項(xiàng)目的核心配置文件,用于管理項(xiàng)目的依賴、插件、構(gòu)建配置等,在Spring Boot項(xiàng)目中,pom.xml文件也扮演著重要的角色,本文將給大家詳細(xì)介紹一下SpringBoot中pom.xml配置,需要的朋友可以參考下
    2023-09-09
  • java代碼抓取網(wǎng)頁(yè)郵箱的實(shí)現(xiàn)方法

    java代碼抓取網(wǎng)頁(yè)郵箱的實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇java代碼抓取網(wǎng)頁(yè)郵箱的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06
  • Java RMI機(jī)制講解

    Java RMI機(jī)制講解

    這篇文章主要介紹了Java RMI機(jī)制講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • java實(shí)現(xiàn)批量導(dǎo)入Excel表格數(shù)據(jù)到數(shù)據(jù)庫(kù)

    java實(shí)現(xiàn)批量導(dǎo)入Excel表格數(shù)據(jù)到數(shù)據(jù)庫(kù)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)批量導(dǎo)入Excel表格數(shù)據(jù)到數(shù)據(jù)庫(kù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • 解決Mybatis查詢方法selectById()主鍵不一致問(wèn)題

    解決Mybatis查詢方法selectById()主鍵不一致問(wèn)題

    這篇文章主要介紹了解決Mybatis查詢方法selectById()主鍵不一致問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10

最新評(píng)論