threadlocal,顧名思義,它不是一個線程,而是線程的一個本地化對象。當工作于多線程中的對象使用threadlocal維護變量時,threadlocal為每個使用該變量的線程配置設定一個獨立的變量副本。是以每一個線程都可以獨立地改變自己的副本,而不會影響其他線程所對應的副本。從線程的角度看,這個變量就像是線程的本地變量,這也是類名中“local”所要表達的意思。
<a></a>
threadlocal的方法很簡單,主要的就是4個方法
那麼threadlocal是如何做到為每一個線程維護一份獨立的變量副本呢?其實實作思路很簡單:在threadlocal類中有一個map,用于存儲沒一個線程的變量副本,map中元素的鍵為線程對象,而值對應線程的變量副本。我們自己也可以提供一個簡單的實作版本:
下面是我在項目中運用threadlocal來實作多線程情況下,使用者資訊的管理session:
threadlocal和線程同步機制都是為了解決多線程中相同變量的通路沖突問題,那麼,threadlocal和線程同步機制相比有什麼優勢呢?
在同步機制中,通過對象的鎖機制保證同一時間隻有一個線程通路變量。這時該變量是多個線程共享的,使用同步機制要求程式缜密的分析什麼時候對變量進行讀寫,什麼時候需要鎖定某個對象,什麼時候釋放對象鎖等繁雜的問題,程式設計和編寫難度相對較大
而threadlocal則從另一個角度來解決多線程的并發通路。threadlocal為每一個線程提供一個獨特的變量副本,進而隔離了多個線程對通路資料的沖突。因為每一個線程都擁有自己的變量副本,進而也就沒有必要對該變量進行同步了。threadlocal提供了線程安全的對象封裝,在編寫多線程代碼時,可以把不安全的變量封裝進threadlocal。
概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式:通路串行化,對象共享化。而threadlocal采用了“以空間換時間”的方式:通路并行化,對象獨享化。前者僅提供一份變量,讓不同的線程排隊通路,而後者為每一個線程都提供了一份變量,是以可以同時通路而互不影響。
我們知道在一般情況下,隻有無狀态的bean才可以在多線程環境下共享,在spring中,絕大部分bean都可以聲明為singleton作用域。就是因為spring對一些bean(如requestcontextholder、transactionsynchronizationmanager、localecontextholder)中非線程安全的“狀态性對象”采用threadlocal進行封裝,讓它們也成為線程安全的“狀态性對象”,因為有狀态的bean就能夠以singleton方式在多線程中正常工作了。
通過檢視transactionsynchronizationmanager源碼可以發現spring事務的工作機制,我們可以自己利用threadlocal來實作自定義的session和transaction管理: