java線程安全問題之靜態變量、實例變量、局部變量

靜態變量:線程非安全。java

靜態變量即類變量,位於方法區,爲全部對象共享,共享一分內存,一旦靜態變量被修改,其餘對象均對修改可見,故線程非安全。安全

實例變量:單例模式(只有一個對象實例存在)線程非安全,非單例線程安全。bash

實例變量爲對象實例私有,在虛擬機的堆中分配,若在系統中只存在一個此對象的實例,在多線程環境下,「猶如」靜態變量那樣,被某個線程修改後,其餘線程對修改都可見,故線程非安全;若是每一個線程執行都是在不一樣的對象中,那對象與對象之間的實例變量的修改將互不影響,故線程安全。多線程

局部變量:線程安全。ide

每一個線程執行時將會把局部變量放在各自棧幀的工做內存中,線程間不共享,故不存在線程安全問題。spa

靜態變量線程安全問題模擬:線程

package com.wxx.demo;


/**
 * @Author : leisure
 * @Date : 2019/1/23
 */
public class VariableTest implements Runnable{

    private static int static_i ;


    @Override
    public void run() {
        static_i = 4;
        System.out.println("[" + Thread.currentThread().getName()
                + "]獲取static_i 的值:" + static_i);
        static_i = 10;
        System.out.println("[" + Thread.currentThread().getName()
                + "]獲取static_i*2的值:" + static_i * 2);
    }

    public static void main(String[] args) {
        VariableTest t = new VariableTest();
        //啓動儘可能多的線程才能很容易的模擬問題
        for (int i = 0; i < 3000; i++)
        {
            //t能夠換成new Test(),保證每一個線程都在不一樣的對象中執行,結果同樣
            new Thread(t, "線程" + i).start();
        }
    }
}

複製代碼

運行結果:code

[線程1479]獲取static_i*2的值:20
[線程1483]獲取static_i 的值:4
[線程1483]獲取static_i*2的值:8
[線程2891]獲取static_i 的值:4
[線程2891]獲取static_i*2的值:20
[線程1689]獲取static_i 的值:10
[線程1689]獲取static_i*2的值:20
複製代碼

根據代碼註釋中模擬的狀況,當線程1執行了static_i = 4; static_i = 10; 後,線程2得到執行權,static_i = 4; 而後當線程1得到執行權執行static_i * 2; 必然輸出結果4*2=8,按照這個模擬,咱們可能會在控制檯看到輸出爲8的結果。或者 當線程1執行了static_i = 4; static_i = 10; 後,線程2得到執行權,咱們可能會在控制檯看到輸出爲獲取static_i 的值:10的結果對象

 實例變量線程安全問題模擬:內存

package com.wxx.demo;


/**
 * @Author : leisure
 * @Date : 2019/1/23
 */
public class VariableTest implements Runnable{

    private  int static_i ;


    @Override
    public void run() {
        static_i = 4;
        System.out.println("[" + Thread.currentThread().getName()
                + "]獲取static_i 的值:" + static_i);
        static_i = 10;
        System.out.println("[" + Thread.currentThread().getName()
                + "]獲取static_i*2的值:" + static_i * 2);
    }

    public static void main(String[] args) {
        VariableTest t = new VariableTest();
        //啓動儘可能多的線程才能很容易的模擬問題
        for (int i = 0; i < 3000; i++)
        {
            //t能夠換成new Test(),保證每一個線程都在不一樣的對象中執行,結果同樣
            new Thread(t, "線程" + i).start();
        }
    }
}


複製代碼

理由同上

局部變量線程安全問題模擬:

package com.wxx.demo;


/**
 * @Author : leisure
 * @Date : 2019/1/23
 */
public class VariableTest implements Runnable{

    private  int static_i ;


    @Override
    public void run() {
        int static_i ;
        static_i = 4;
        System.out.println("[" + Thread.currentThread().getName()
                + "]獲取static_i 的值:" + static_i);
        static_i = 10;
        System.out.println("[" + Thread.currentThread().getName()
                + "]獲取static_i*2的值:" + static_i * 2);
    }

    public static void main(String[] args) {
        VariableTest t = new VariableTest();
        //啓動儘可能多的線程才能很容易的模擬問題
        for (int i = 0; i < 3000; i++)
        {
            //t能夠換成new Test(),保證每一個線程都在不一樣的對象中執行,結果同樣
            new Thread(t, "線程" + i).start();
        }
    }
}



複製代碼

控制檯沒有出現異常數據。


靜態方法是線程安全的

先看一個類

public class Test{

public static String hello(String str){

String tmp="";

tmp = tmp+str;

return tmp;

}

}

hello方法會不會有多線程安全問題呢?沒有!!

靜態方法若是沒有使用靜態變量,則沒有線程安全問題。

爲何呢?由於靜態方法內聲明的變量,每一個線程調用時,都會新建立一份,而不會共用一個存儲單元。好比這裏的tmp,每一個線程都會建立本身的一份,所以不會有線程安全問題

注意,靜態變量,因爲是在類加載時佔用一個存儲區,每一個線程都是共用這個存儲區的,因此若是在靜態方法裏使用了靜態變量,這就會有線程安全問題!

相關文章
相關標籤/搜索