Spring框架中的bean 或者說組件,默認是單例的。
單例模式確保了某個類只有一個實例,並且自行實例化,向整個系統提供這個實例。
在多線程的情況下,Web容器會向每個請求分配一個線程。這些線程會執行對應的業務邏輯。如果在執行的時候對單例對象進行了修改,則必須考慮到線程同步的問題。
同步機制
ThreadLocal 和 線程同步機制
線程同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什么時候對變量進行讀寫,什么時候需要鎖定某個對象,什么時候釋放對象鎖等繁雜的問題。
ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。
對於多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。
在spring 中是使用 ThreadLocal 解決線程安全問題
線程安全問題主要是全局變量和靜態變量引起的。
若每個線程中對全局變量、靜態變量讀操作,而無寫操作,一般來說這個全局變量是線程安全的。
若多個線程同時執行寫操作,需要考慮線程同步問題,否則影響線程安全。
spring 使用ThreadLocal 實現高並發下 共享資源的同步。
原理:
為每一個使用該變量的線程都提供一個變量值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。從線程的角度看,就好像每一個線
程都完全擁有該變量。【每個線程其實是改變的是自己線程的副本,而不是真正要改變的變量,所以效果就是每個線程都有自己的,“這其實就將共享變相為人人有份!”】
ThreadLocal 如何實現為每一個變量維護變量的副本。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }