靜態變量:線程非安全。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,每一個線程都會建立本身的一份,所以不會有線程安全問題
注意,靜態變量,因爲是在類加載時佔用一個存儲區,每一個線程都是共用這個存儲區的,因此若是在靜態方法裏使用了靜態變量,這就會有線程安全問題!