單實例多線程下成員變量的線程安全

一.靜態方法

靜態方法屬於類本生,在類裝載的時候就會被裝載到內存,不會進行自動銷燬,會一直存於內存中,只有jvm關閉,其才會在內存中銷燬。

二.非靜態方法

非靜態方法是屬於實例對象的,對象實例化後會分配內存,必須通過類的實例來進行引用。不會常駐內存,當實例對象被jvm回收後,其也會跟著銷燬。

三.靜態成員變量

靜態成員變量位於方法區,其是線程非安全的,被該類下的所有對象共享,共享一份內存,一旦靜態變量被修改,其他對象均對修改值可見。

四.局部變量

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

五.實例成員變量

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

實例變量為對象實例私有,在虛擬機的堆中分配,若在系統中只存在一個此對象的實例,在多線程環境下,"猶如"靜態變量那樣,被某個線程修改後,其他線程對修改均可見,故線程非安全;

如果每個線程執行都是在不同的對象中,那對象與對象之間的實例變量的修改將互不影響,故線程安全。

六.下面詳細分析單實例成員變量如何實現線程安全

線程不安全測試類:SingleObjectTest.java,如圖6.1

開啟200個線程,結果下圖所示

單實例多線程下成員變量的線程安全

開啟了200個線程,從圖6.2的結果來看,如果是線程安全的,應該nextValue的開始值都應該是1,然後加1後,變動的值應該是2,但顯然結果不是如此,故論證了單實例多線程下成員變量是線程不安全的。

既然單實例多線程下成員變量是不安全的,如何做到線程安全呢?下面就需要引入ThreadLocal類,如下圖所示

單實例多線程下成員變量的線程安全

開啟了3個線程,結果如圖6.4所示

單實例多線程下成員變量的線程安全

看到這樣的結果,讀者或許會納悶,ThreadLocal不是線程安全的?怎麼結果也是不對的呢?

其實是因為在線程池的背景下,即使使用ThreadLocal也會存在線程不安全的情況,這就需要讀者對線程池有個深入的瞭解才行,一般情況下,如果頻繁地創建線程,會存在很大的資源開銷的,為了提升資源的利用率,引入線程池是個很好的優化方案,但引入線程池ThreadLocal的變量值也需要銷燬才會迴歸初始值,如下圖所示

單實例多線程下成員變量的線程安全

結果如下圖所示

單實例多線程下成員變量的線程安全

當ThreadLocal每次操作後都執行remove()操作,採用線程池的方案執行單例多線程,成員變量才是線程安全的。

您的關注是我的持續動力,咱們下期分享~bye


分享到:


相關文章: