java內存詳解

2、JAVA中的內存模型

程序運行的時候,內存主要由如下部分組成:java

  1. :全部線程共享一個堆;存放的都是new 出來的對象;由垃圾回收器回收;
  2. 方法區:全部線程共享一個方法區;裏面存放的內容有點雜,能夠認爲是除堆和棧中的其它東西(如類信息,靜態變量,常量,代碼等);Java虛擬機規範規定能夠不對方法區進行垃圾回收,當並非不回收,主要看具體虛擬機的實現,好比能夠回收一些廢棄常量和無用的類;
  3. 程序計數器:也叫PC,存放下一條指令所在單元的地址的地方;
  4. JAVA棧:每一個線程都有一個本身的JAVA棧;存放的通常是方法的局部變量,方法出口信息等;方法調用過程當中,自動壓棧出棧;ps:棧空間大小是有限制的;
  5. 本地方法棧:與JAVA棧相似,區別是使用的對象不同,本地方法棧是給Native方法使用的,JAVA棧是給JAVA方式使用的;

附一張圖片,會對java虛擬機有個總體的認識;
多線程

圖片來自https://www.zybuluo.com/867976167/note/51071ide

 3、多線程訪問共享內存狀況

當多個線程執行同一個方法的時候,函數

何時可能會出現異常結果:url

多個線程共享一塊內存區域,在不加任何保護狀況下,對其操做;spa

何時可能會獲得正確的結果:線程

不使用共享內存,每一個線程內存空間相互獨立;code

多線程共享一塊內存區域,可是對這塊共享區域加鎖訪問;對象

4、實例說明

狀況一(多個線程共享一塊內存區域,在不加任何保護狀況下,對其操做):blog

寫一個含靜態方法的類,求和,方法內用了一個靜態全局s(多個線程能夠同時訪問):

複製代碼
package com.pichen.java.static_;

public class StaticTest {

    private static int s = 0;
    public static int sum(int n){
        s = 0;
        for(int i = 0; i <= n; i++){
            s += i;
            
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return s;
    }
}
複製代碼

寫一個Thread,調用上面的靜態方法:

複製代碼
package com.pichen.java.static_;

public class ThreadCount implements Runnable{


    @Override
    public void run() {
        while(true){
            System.out.println(Thread.currentThread().getName() +":" +StaticTest.sum(100));
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }

}
複製代碼

寫個Main函數,起三個線程,觀察運行結果,基本都是錯誤的:

複製代碼
package com.pichen.java.static_;


public class Main {

    public static void main(String[] args) {

        ThreadCount t1 = new ThreadCount();
        new Thread(t1).start();
        
        ThreadCount t2 = new ThreadCount();
        new Thread(t2).start();
        
        ThreadCount t3 = new ThreadCount();
        new Thread(t3).start();
    }
}
複製代碼

運行結果不符合預期:

複製代碼
Thread-0:13968
Thread-1:13968
Thread-2:13968
Thread-0:13033
Thread-1:13033
Thread-2:13033
Thread-1:14725
Thread-0:14725
複製代碼

 緣由:多個線程同時對靜態全局變量s進行操做致使;

ps:這裏的例子是靜態全局變量s,其實有不少種狀況會引發結果異常問題,如在main方法中new出了一個對象,new出來的對象是存放在堆中的,多個線程共享,此時若是多線程同時操做該對象的話,也是有可能產生錯誤結果;

狀況二(不使用共享內存,每一個線程內存空間相互獨立):

修改靜態sum方法,使用局部變量s,以下:

複製代碼
package com.pichen.java.static_;

public class StaticTest {

    private static int s = 0;
    public static int sum(int n){
        int s = 0;
        for(int i = 0; i <= n; i++){
            s += i;
            
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return s;
    }
}
複製代碼

運行程序,結果正確:

複製代碼
Thread-1:5050
Thread-0:5050
Thread-2:5050
Thread-0:5050
Thread-2:5050
Thread-1:5050
Thread-0:5050
複製代碼

狀況三(多線程共享一塊內存區域,可是對這塊共享區域加鎖訪問):

複製代碼
package com.pichen.java.static_;

public class StaticTest {

    private static int s = 0;
    public synchronized static int sum(int n){
        s = 0;
        for(int i = 0; i <= n; i++){
            s += i;
            
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return s;
    }
}
複製代碼

@author   風同樣的碼農
@blog_urlhttp://www.cnblogs.com/chenpi/

運行程序,結果正確:

複製代碼
Thread-1:5050
Thread-0:5050
Thread-2:5050
Thread-0:5050
Thread-2:5050
Thread-1:5050
Thread-0:5050
相關文章
相關標籤/搜索