1. 程式人生 > >併發程式設計---執行緒封閉(棧封閉和ThreadLocal)

併發程式設計---執行緒封閉(棧封閉和ThreadLocal)

    在多執行緒環境中,如果多個執行緒同時訪問一個共同的可變變數,我們稱這個變數為共享變數,如果不做任何措施,很可能會引起執行緒安全問題。那麼如何解決這個執行緒安全問題是我們要考慮的。我們通常的做法是使用同步,但是我們有沒有想過執行緒的安全問題是因為共享,那如果在某些場景下我們不共享資料呢?

    首先我們想到的是如果僅在單執行緒下訪問資料,就不需要同步,這種技術被稱為執行緒封閉。它是實現執行緒安全的最簡單的方法。當某些物件或資料被封閉在一個執行緒中時,這種做法會自動實現執行緒安全性,就算被封閉的物件本身並不是執行緒安全的,但由於是在單執行緒內部訪問,所以它也變成了執行緒安全的了。

    棧封閉

    當我們在寫一個方法的時候,在方法內部定義了一些區域性變數,我們根據我們所謂的經驗知道這些區域性變數是執行緒安全的。但是為什麼這些區域性變數是執行緒安全的呢? 我們先來了解下Jvm執行時記憶體的一塊區域---Java虛擬機器棧。我們通常所說的“”就是指的Java虛擬機器棧,或者說是虛擬機器棧中區域性變量表部分。首先Java虛擬機器棧是私有的,它的生命週期和執行緒相同。Java虛擬機器棧描述的Java方法執行的記憶體模型每個方法在執行時都會建立一個“棧幀”,用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊。每一個方法從呼叫直至執行完成的過程,就對應這個一個棧幀在虛擬機器中入棧到出棧的過程

     我們回到剛才那個問題,為什麼區域性變數是執行緒安全的呢?因為區域性變數存放在虛擬機器棧中,而虛擬機器棧是執行緒私有的,既然執行緒不共享,所以它是執行緒安全的。封閉棧的執行緒安全性體現在Java虛擬機器的記憶體特性。

 

    ThreadLocal類

    ThreadLocal也提供了執行緒封閉的特性,簡單的理解就是它給每個執行緒都提供了一個存放執行緒私有變數的的區域(ThreadLocalMap),這個區域是執行緒私有的,ThreadLocal提供了get和set等方法來操作這些變數,get總是返回由當前執行緒在呼叫get時設定的最新值。 那麼ThreadLocal是如何來實現這種機制的呢?