Java多執行緒/併發12、多執行緒訪問static變數

唐大麥發表於2017-04-28

類的成員分為兩類,靜態成員(static member)和例項成員(instance member)。靜態成員屬於類;例項成員則屬於物件,即類的例項。
先看一個類:

public class staticDemo {
    static int result;
    static int Addone(Integer num){
        Integer inner_result=num++;
        return inner_result;
    }
    public static void main(String[] args) {

    }
}

Addone方法會不會有多執行緒安全問題呢?沒有!
靜態方法如果沒有使用靜態變數,則沒有執行緒安全問題。
為什麼呢?因為靜態方法內宣告的變數是區域性變數,它放在java棧中的,每個執行緒呼叫時,都會新建立一份,而不會共用一個儲存單元。比如這裡的inner_result,每個執行緒都會建立自己的一份,因此不會有執行緒安全問題。

當多個執行緒執行同一個方法的時候,什麼時候可能會出現異常結果?
多個執行緒共享一塊記憶體區域,在不加任何保護情況下對其操作就會出現異常結果,因為靜態成員(static member)作為公共變數,就是放在共享記憶體區域的。
比如上面那個例子,如果我在方法中用了靜態變數result,就會導致問題

public class staticDemo {
    static int result;
    static int Addone(Integer num){
        result=num++;
        return result;
    }
    public static void main(String[] args) {

    }
}

什麼時候可能會得到正確的結果:

  • 不使用共享記憶體,每個執行緒記憶體空間相互獨立;
  • 多執行緒共享一塊記憶體區域,但是對這塊共享區域加鎖訪問。對呼叫static變數的方法使用lock或synchronized

《深入理解java虛擬機器》知識點

程式執行的時候,記憶體主要由以下部分組成:
堆:所有執行緒共享一個堆;存放的都是new 出來的物件;由垃圾回收器回收;
方法區:所有執行緒共享一個方法區;裡面存放的內容有點雜,可以認為是除堆和棧中的其它東西(如類資訊,靜態變數,常量,程式碼等);Java虛擬機器規範規定可以不對方法區進行垃圾回收,當然並不是不回收,主要看具體虛擬機器的實現,比如可以回收一些廢棄常量和無用的類;
程式計數器:也叫PC,存放下一條指令所在單元的地址的地方;
JAVA棧:每個執行緒都有一個自己的JAVA棧;存放的一般是方法的區域性變數,方法出口資訊等;方法呼叫過程中,自動壓棧出棧;ps:棧空間大小是有限制的;
本地方法棧:與JAVA棧類似,區別是使用的物件不一樣,本地方法棧是給Native方法使用的,JAVA棧是給JAVA方式使用的;
附一張圖片,會對java虛擬機器有個整體的認識;
這裡寫圖片描述

相關文章