java线程安全问题之静态变量、实例变量、局部变量
轉(zhuǎn)載
?
java多線(xiàn)程編程中,存在很多線(xiàn)程安全問(wèn)題,至于什么是線(xiàn)程安全呢,給出一個(gè)通俗易懂的概念還是蠻難的,如同《java并發(fā)編程實(shí)踐》中所說(shuō):
寫(xiě)道?
給線(xiàn)程安全下定義比較困難。存在很多種定義,如:“一個(gè)類(lèi)在可以被多個(gè)線(xiàn)程安全調(diào)用時(shí)就是線(xiàn)程安全的”。??
?此處不贅述了,首先給出靜態(tài)變量、實(shí)例變量、局部變量在多線(xiàn)程環(huán)境下的線(xiàn)程安全問(wèn)題結(jié)論,然后用示例驗(yàn)證,請(qǐng)大家擦亮眼睛,有錯(cuò)必究,否則誤人子弟!
?
?
?
靜態(tài)變量:線(xiàn)程非安全。
?
靜態(tài)變量即類(lèi)變量,位于方法區(qū),為所有對(duì)象共享,共享一份內(nèi)存,一旦靜態(tài)變量被修改,其他對(duì)象均對(duì)修改可見(jiàn),故線(xiàn)程非安全。
?
?
?
實(shí)例變量:單例模式(只有一個(gè)對(duì)象實(shí)例存在)線(xiàn)程非安全,非單例線(xiàn)程安全。
?
實(shí)例變量為對(duì)象實(shí)例私有,在虛擬機(jī)的堆中分配,若在系統(tǒng)中只存在一個(gè)此對(duì)象的實(shí)例,在多線(xiàn)程環(huán)境下,“猶如”靜態(tài)變量那樣,被某個(gè)線(xiàn)程修改后,其他線(xiàn)程對(duì)修改均可見(jiàn),故線(xiàn)程非安全;如果每個(gè)線(xiàn)程執(zhí)行都是在不同的對(duì)象中,那對(duì)象與對(duì)象之間的實(shí)例變量的修改將互不影響,故線(xiàn)程安全。
?
局部變量:線(xiàn)程安全。
?
每個(gè)線(xiàn)程執(zhí)行時(shí)將會(huì)把局部變量放在各自棧幀的工作內(nèi)存中,線(xiàn)程間不共享,故不存在線(xiàn)程安全問(wèn)題。
?
?
?
靜態(tài)變量線(xiàn)程安全問(wèn)題模擬:
?
----------------------------------------------------------------------------------
?
?
?
Java代碼???
?
?
?
?
?
?
根據(jù)代碼注釋中模擬的情況,當(dāng)線(xiàn)程1執(zhí)行了static_i = 4;??static_i = 10; 后,線(xiàn)程2獲得執(zhí)行權(quán),static_i = 4;?然后當(dāng)線(xiàn)程1獲得執(zhí)行權(quán)執(zhí)行static_i * 2;? 必然輸出結(jié)果4*2=8,按照這個(gè)模擬,我們可能會(huì)在控制臺(tái)看到輸出為8的結(jié)果。
?
寫(xiě)道?
[線(xiàn)程27]獲取static_i 的值:4?[線(xiàn)程22]獲取static_i*2的值:20?
[線(xiàn)程28]獲取static_i 的值:4?
[線(xiàn)程23]獲取static_i*2的值:8?
[線(xiàn)程29]獲取static_i 的值:4?
[線(xiàn)程30]獲取static_i 的值:4?
[線(xiàn)程31]獲取static_i 的值:4?
[線(xiàn)程24]獲取static_i*2的值:20
?
?看紅色標(biāo)注的部分,確實(shí)出現(xiàn)了我們的預(yù)想,同樣也證明了我們的結(jié)論。
?
?
?
實(shí)例變量線(xiàn)程安全問(wèn)題模擬:
?
----------------------------------------------------------------------------------
?
Java代碼???
?
?
?
?
按照本文開(kāi)頭的分析,猶如靜態(tài)變量那樣,每個(gè)線(xiàn)程都在修改同一個(gè)對(duì)象的實(shí)例變量,肯定會(huì)出現(xiàn)線(xiàn)程安全問(wèn)題。
?
寫(xiě)道
?
[線(xiàn)程66]獲取instance_i 的值:10?
[線(xiàn)程33]獲取instance_i*2的值:20?
[線(xiàn)程67]獲取instance_i 的值:4?
[線(xiàn)程34]獲取instance_i*2的值:8?
[線(xiàn)程35]獲取instance_i*2的值:20?
[線(xiàn)程68]獲取instance_i 的值:4
?
?
?
看紅色字體,可知單例情況下,實(shí)例變量線(xiàn)程非安全。
?
?
?
將new Thread(t, "線(xiàn)程" + i).start();改成new Thread(new Test(), "線(xiàn)程" + i).start();模擬非單例情況,會(huì)發(fā)現(xiàn)不存在線(xiàn)程安全問(wèn)題。
?
?
?
?
?
局部變量線(xiàn)程安全問(wèn)題模擬:
?
----------------------------------------------------------------------------------
?
?
?
Java代碼???
?
?
?
?
控制臺(tái)沒(méi)有出現(xiàn)異常數(shù)據(jù)。
?
?
?
---------------------------------------------------------------
?
以上只是通過(guò)簡(jiǎn)單的實(shí)例來(lái)展示靜態(tài)變量、實(shí)例變量、局部變量等的線(xiàn)程安全問(wèn)題,
?
并未進(jìn)行底層的分析,下一篇將對(duì)線(xiàn)程問(wèn)題的底層進(jìn)行剖析。
?
?
?
?
靜態(tài)方法是線(xiàn)程安全的
?
?
?
先看一個(gè)類(lèi)
?
public class? Test{
?
public static? String hello(String str){
?
??? String?tmp="";
?
????tmp? =??tmp+str;
?
?? return?tmp;
?
}
?
}
?
hello方法會(huì)不會(huì)有多線(xiàn)程安全問(wèn)題呢?沒(méi)有!!
?
靜態(tài)方法如果沒(méi)有使用靜態(tài)變量,則沒(méi)有線(xiàn)程安全問(wèn)題。
?
為什么呢?因?yàn)?strong style="color:#000000;background-color:#a0ffff;">靜態(tài)方法內(nèi)聲明的變量,每個(gè)線(xiàn)程調(diào)用時(shí),都會(huì)新創(chuàng)建一份,而不會(huì)共用一個(gè)存儲(chǔ)單元。比如這里的tmp,每個(gè)線(xiàn)程都會(huì)創(chuàng)建自己的一份,因此不會(huì)有線(xiàn)程安全問(wèn)題
?
?
?
注意,靜態(tài)變量,由于是在類(lèi)加載時(shí)占用一個(gè)存儲(chǔ)區(qū),每個(gè)線(xiàn)程都是共用這個(gè)存儲(chǔ)區(qū)的,所以如果在靜態(tài)方法里使用了靜態(tài)變量,這就會(huì)有線(xiàn)程安全問(wèn)題!
總結(jié):只要方法內(nèi)含有靜態(tài)變量,就是非線(xiàn)程安全的
總結(jié)
以上是生活随笔為你收集整理的java线程安全问题之静态变量、实例变量、局部变量的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SSL 的 java 实现
- 下一篇: 查看was中项目类的加载顺序