<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # 內存劃分 ![](https://img.kancloud.cn/4b/57/4b5712afa06d951acc088770bce0ed56_674x314.png) # java對象在內存的分配 ~~~java public class Student { private String name; private static Birthday birthday = new Birthday(); public Student(String name) { this.name = name; } public static void main(String[] args) { Student s = new Student("zhangsan"); int age = 10; System.out.println(age); } } class Birthday { private int year = 2010; private int month = 10; private int day = 1; } ~~~ ![](https://img.kancloud.cn/63/71/6371ddd8bc0eae5e73a5678a1d560ded_669x433.png) # 從內存區域來分析 * **虛擬機棧**:只存放局部變量 * **堆**:存儲對象的實例 * **方法區**:存放Class信息和常量信息。 # 從變量的角度來分析 * **局部變量:**存放在虛擬機棧中(具體應為\[棧->棧幀->局部變量表\]) * 基本類型的值直接存在棧中。如age=10 * 如果是對象的實例,則只存儲對象實例的引用。如s=ref * **實例變量:**存放在堆中的對象實例中。如Student的實例變量 name=ref * **靜態變量:**存放在方法區中的常量池中。如Student.class中的birthday=ref。 * 如果常量的類型是對象的實例則只存儲對象實例的引用地址 > 通過變量的角度來分析,我們就可以了解為什么靜態變量不用new就能調用,而實例變量必須new出對象,才能調用。 # 內存模型 ![](https://img.kancloud.cn/62/6e/626ed3424687763229e5f2b070e4c4e7_1365x575.png) java的并發采用的是共享內存模型(而非消息傳遞模型) Java線程之間的通信由Java內存模型(JMM)控制,JMM決定一個線程對共享變量的寫入何時對另一個線程可見. JMM定義了線程和主內存之間的抽象關系:線程之間的共享變量存儲在主內存(main memory)中,每個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本 ![](https://img.kancloud.cn/66/4f/664f1a8e9c40a892c007f8a4fbfa7948_408x362.png) 圖中的共享變量為:實例變量和靜態變量。(局部變量是線程私有的不存在競爭) 從圖中看,線程A和線程B進行通訊必須通過主內存 1. 線程A修改了一個共享變量,并刷新到主內存中 2. 線程B從主內存讀取A修改過的共享變量 **注意:** 1. 線程對共享變量的所有操作都必須在自己的本地內存中進行,不能直接從主內存中讀寫。 2. 不同線程之間無法直接訪問其它線程的本地內存,線程間的變量值的傳遞,必須通過主內存來完成。 # 指令重排序 指令重排序是JVM為了優化指令,提高程序運行效率,編譯器、處理器也遵循這樣一個目標. 重排序分三種類型: ![](https://img.kancloud.cn/a0/19/a019948058d3daa64ff24c6d7948ebb3_536x66.png) 1. 編譯器優化的重排序。編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序。 2. 指令級并行的重排序。現代處理器采用了指令級并行技術(Instruction-Level Parallelism, ILP)來將多條指令重疊執行。如果不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序。 3. 內存系統的重排序。由于處理器使用緩存和讀/寫緩沖區,這使得加載和存儲操作看上去可能是在亂序執行。 # 內存可見性 內存可見性簡單描述:當主內存中的一個共享變量在多個線程的本地內存中都存在副本,如果一個線程修改共享變量,其它線程也應該能看到被修改后的值。 > **要實現共享變量的可見性,必須實現兩點:** 1. 線程修改后的共享變量值能夠及時的從工作內存刷新到主內存中。 2. 其它線程能夠及時把共享變量的最新值從主內存更新到自己的本地內存中。 # happens-before規則 JMM使用happens-before的概念來闡述操作之間的內存可見性。在JMM中,如果一個操作執行的結果**需要對**另一個操作**可見**,那么這兩個操作就必須存在happens-before關系。 **happens-before規則如下:** 1. 程序順序規則:一個線程中的每個操作,happens- before 于該線程中的任意后續操作。 2. 監視器鎖規則:對一個監視器鎖的解鎖,happens- before 于隨后對這個監視器鎖的加鎖。 3. volatile變量規則:對一個volatile域的寫,happens- before 于任意后續對這個volatile域的讀。 4. 傳遞性:如果A happens- before B,且B happens- before C,那么A happens- before C。 > 注意,兩個操作之間具有happens-before關系,并不意味著前一個操作必須要在后一個操作之前執行!happens-before僅僅要求前一個操作(執行的結果)對后一個操作可見,且前一個操作按順序排在第二個操作之前。 # as-if-serial as-if-serial定義重排序的規則。 as-if-serial語義的意思:不管怎么重排序,程序的執行結果都不能被改變。編譯器、runtime和處理器都必須遵守as-if-serial規則。 ~~~java int a=2; //A int b=3; //B int c=a*b; //C ~~~ ![](https://img.kancloud.cn/8f/74/8f74b4bb1190da25154080d938703bc9_385x145.png) > **注意:** 1. 重排序不會給單線程程序帶來內存可見性問題 2. 多線程程序并發交叉執行時,重排序可能會造成內存可見性問題 上面程序的happens-before的關系: 1. A happens-before B 2. B happens-before C 3. A happens-before C (happens-before的傳遞性) 在這里A happens-before B, 但實際執行B可以排在A之前執行。JMM僅僅要求前一個操作對后一個操作可見,且前一個操作按順序排在第二個操作之前。 > 這里A的執行結果**不需要**對操作B**可見** # 可見性與原子性 ? ?可見性:一個線程對共享變量的修改,更夠及時的被其他線程看到 ? ?原子性:即不可再分了,不能分為多步操作。比如賦值或者return。比如"a = 1;"和 "return a;"這樣的操作都具有原子性。類似"a += b"這樣的操作不具有原子性,在某些JVM中"a += b"可能要經過這樣三個步驟: ① 取出a和b ② 計算a+b ③ 將計算結果寫入內存 1. Synchronized:保證可見性和原子性 ? ? Synchronized能夠實現原子性和可見性;在Java內存模型中,synchronized規定,線程在加鎖時,先清空工作內存→在主內存中拷貝最新變量的副本到工作內存→執行完代碼→將更改后的共享變量的值刷新到主內存中→釋放互斥鎖。 2. Volatile:保證可見性,但不保證操作的原子性 ? ? Volatile實現內存可見性是通過store和load指令完成的;也就是對volatile變量執行寫操作時,會在寫操作后加入一條store指令,即強迫線程將最新的值刷新到主內存中;而在讀操作時,會加入一條load指令,即強迫從主內存中讀入變量的值。但**volatile不保證volatile變量的原子性 ** **Synchronized和Volatile的比較** 1. Synchronized保證內存可見性和操作的原子性 2. Volatile只能保證內存可見性 3. Volatile不需要加鎖,比Synchronized更輕量級,并不會阻塞線程(volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。) 4. volatile標記的變量不會被編譯器優化,而synchronized標記的變量可以被編譯器優化(如編譯器重排序的優化). 5. volatile是變量修飾符,僅能用于變量,而synchronized是一個方法或塊的修飾符。
                  <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>

                              哎呀哎呀视频在线观看