<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### JAVA內存模型\(JMM\) 定義:Java內存模型即Java Memory Model,簡稱JMM; > **JMM定義了Java虛擬機\(JVM\)在計算機內存\(RAM\)中的工作方式** Java內存模型(Java Memory Model ,JMM)就是一種符合內存模型規范的,屏蔽了各種硬件和操作系統的訪問差異的,保證了Java程序在各種平臺下對內存的訪問都能保證效果一致的機制及規范,現在最新的規范為JSR-133。 這套規范包含: * 線程之間如何通過內存通信 * 線程之間通過什么方式通信才合法,才能得到期望的結果 JSR133為Java語言定義了一個新的內存模型,它修復了早期內存模型中的缺陷 在編譯器各種優化及多種類型的微架構平臺上,Java語言規范制定者試圖創建一個虛擬的概念并傳遞到Java程序員,讓他們能夠在這個虛擬的概念上寫出線程安全的程序來,而編譯器實現者會根據Java語言規范中的各種約束在不同的平臺上達到Java程序員所需要的線程安全這個目的 在多處理器下,為了保證各個處理器的緩存是一致的,就會實現緩存一致性協議,每個處理器通過嗅探在總線上傳播的數據來檢查自己緩存的值是不是過期了,當處理器發現自己緩存行對應的內存地址被修改,就會將當前處理器的緩存行設置成無效狀態,當處理器對這個數據進行修改操作的時候,會重新從系統內存中把數據讀到處理器緩存里; ![](https://img.kancloud.cn/03/86/03864e32d548705ebece4362f5cee024_1148x338.png) ![](https://img.kancloud.cn/03/73/0373e0baf323eee422e31c207e763a45_1868x836.png) _在處理器層面上,內存模型定義了一個充要條件,“讓當前的處理器可以看到其他處理器寫入到內存的數據”以及“其他處理器可以看到當前處理器寫入到內存的數據”。有些處理器有很強的內存模型\(strong memory model\),能夠讓所有的處理器在任何時候任何指定的內存地址上都可以看到完全相同的值。而另外一些處理器則有較弱的內存模型(weaker memory model),在這種處理器中,必須使用內存屏障(一種特殊的指令)來刷新本地處理器緩存并使本地處理器緩存無效,目的是為了讓當前處理器能夠看到其他處理器的寫操作或者讓其他處理器能看到當前處理器的寫操作。這些內存屏障通常在lock和unlock操作的時候完成。內存屏障在高級語言中對程序員是不可見的_ **Java包含了幾個語言級別的關鍵字,包括:volatile, final以及synchronized,目的是為了幫助程序員向編譯器描述一個程序的并發需求**。Java內存模型定義了volatile和synchronized的行為,更重要的是保證了同步的java程序在所有的處理器架構下面都能正確的運行 ![](https://box.kancloud.cn/2016-08-16_57b2b822b6973.png) 從上圖來看,線程A與線程B之間如要通信的話,必須要經歷下面2個步驟: 1. 首先線程A把本地內存A中更新過的共享變量刷新到主內存中去。 2. 然后線程B到主內存中去讀取線程A之前已更新過的共享變量。 下面通過示意圖來說明這兩個步驟: ![](https://box.kancloud.cn/2016-08-16_57b2b822d2588.png) 如上圖所示,本地內存A和B有主內存中共享變量x的副本。假設初始時,這三個內存中的x值都為0。線程A在執行時,把更新后的x值(假設值為1)臨時存放在自己的本地內存A中。當線程A和線程B需要通信時,線程A首先會把自己本地內存中修改后的x值刷新到主內存中,此時主內存中的x值變為了1。隨后,線程B到主內存中去讀取線程A更新后的x值,此時線程B的本地內存的x值也變為了1。 從整體來看,這兩個步驟實質上是線程A在向線程B發送消息,而且這個通信過程必須要經過主內存。JMM通過控制主內存與每個線程的本地內存之間的交互,來為java程序員提供內存可見性保證。 ### Java內存模型的抽象結構 在Java中,所有實例域、靜態域和數組元素都存儲在堆內存中,堆內存在線程之間共享;局部變量(LocalVariables),方法定義參數(Java語言規范稱之為FormalMethodParameters)和異常處理器參數(ExceptionHandlerParameters)不會在線程之間共享,它們不會有內存可見性問題,也不受內存模型的影響; Java線程之間的通信由Java內存模型(本文簡稱為JMM)控制,JMM決定一個線程對共享變量的寫入何時對另一個線程可見。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關系:線程之間的共享變量存儲在主內存(MainMemory)中,每個線程都有一個私有的本地內存(LocalMemory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,并不真實存在。它涵蓋了緩存、寫緩沖區、寄存器以及其他的硬件和編譯器優化; JVM中運行的每個線程都擁有自己的線程棧,線程棧包含了當前線程執行的方法調用相關信息,我們也把它稱作調用棧。隨著代碼的不斷執行,調用棧會不斷變化。 線程棧還包含了當前方法的所有本地變量信息。一個線程只能讀取自己的線程棧,也就是說,線程中的本地變量對其它線程是不可見的。即使兩個線程執行的是同一段代碼,它們也會各自在自己的線程棧中創建本地變量,因此,每個線程中的本地變量都會有自己的版本。 所有原始類型\(boolean,byte,short,char,int,long,float,double\)的本地變量都直接保存在線程棧當中,對于它們的值各個線程之間都是獨立的。對于原始類型的本地變量,一個線程可以傳遞一個副本給另一個線程,但它們之間是無法共享的。 堆區包含了Java應用創建的所有對象信息,不管對象是哪個線程創建的,其中的對象包括原始類型的封裝類(如Byte、Integer、Long等等)。不管對象是屬于一個成員變量還是方法中的本地變量,它都會被存儲在堆區。 下圖展示了調用棧和本地變量都存儲在棧區,對象都存儲在堆區: ![](https://img.kancloud.cn/60/16/60161ffab995dece22e7515dd37fa877_486x435.png) 特性 * 一個本地變量如果是原始類型,那么它會被完全存儲到棧區; * 一個本地變量也有可能是一個對象的引用,這種情況下,這個本地引用會被存儲到棧中,但是對象本身仍然存儲在堆區。 * 對于一個對象的成員方法,這些方法中包含本地變量,仍需要存儲在棧區,即使它們所屬的對象在堆區。 * 對于一個對象的成員變量,不管它是原始類型還是包裝類型,都會被存儲到堆區。 * static類型的變量以及類本身相關信息都會隨著類本身存儲在方法區; 堆中的對象可以被多線程共享。如果一個線程獲得一個對象的引用,它便可訪問這個對象的成員變量。如果兩個線程同時調用了同一個對象的同一個方法,那么這兩個線程便可同時訪問這個對象的成員變量,但是對于本地變量,每個線程都會拷貝一份到自己的線程棧中,下圖展示了上面描述的過程: ![](https://box.kancloud.cn/2016-08-19_57b665e81b0ef.png) ### 支撐Java內存模型的基礎原理 * **指令重排序** * **數據依賴性** 如果兩個操作訪問同一個變量,其中一個為寫操作,此時這兩個操作之間存在數據依賴性。 編譯器和處理器不會改變存在數據依賴性關系的兩個操作的執行順序,即不會重排序。 | 名稱 | 代碼示例 | 說明 | | :--- | :--- | :--- | | 寫后讀 | a = 1;b = a; | 寫一個變量之后,再讀這個位置。 | | 寫后寫 | a = 1;a = 2; | 寫一個變量之后,再寫這個變量。 | | 讀后寫 | a = b;b = 1; | 讀一個變量之后,再寫這個變量。 | * **as-if-serial** 不管怎么重排序,單線程下的執行結果不能被改變,編譯器、runtime和處理器都必須遵守as-if-serial語義 ``` double pi = 3.14; //A double r = 1.0; //B double area = pi * r * r; //C ``` ``` 上面三個操作的數據依賴關系如下圖所示: ``` ![](http://img.my.csdn.net/uploads/201302/06/1360143739_6151.png) 如上圖所示,A和C之間存在數據依賴關系,同時B和C之間也存在數據依賴關系。因此在最終執行的指令序列中,C不能被重排序到A和B的前面(C排到A和B的前面,程序的結果將會被改變)。但A和B之間沒有數據依賴關系,編譯器和處理器可以重排序A和B之間的執行順序。下圖是該程序的兩種執行順序: ![](http://img.my.csdn.net/uploads/201302/06/1360143751_3794.png) as-if-serial語義把單線程程序保護了起來,遵守as-if-serial語義的編譯器,runtime 和處理器共同為編寫單線程程序的程序員創建了一個幻覺:單線程程序是按程序的順序來執行的。**as-if-serial語義使單線程程序員無需擔心重排序會干擾他們,也無需擔心內存可見性問題**。 _**參考資料**_ 【Java內存模型FAQ(一) 什么是內存模型】 [http://ifeve.com/memory-model](http://ifeve.com/memory-model) 【全面理解Java內存模型】[https://blog.csdn.net/suifeng3051/article/details/52611310](https://blog.csdn.net/suifeng3051/article/details/52611310) 【深入理解Java內存模型(一)——基礎】 [http://www.infoq.com/cn/articles/java-memory-model-1](http://www.infoq.com/cn/articles/java-memory-model-1) 【Java內存模型FAQ】 [http://ifeve.com/jmm-faq/](http://ifeve.com/jmm-faq/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看