單例的好處:
1 減少請求時候創建對象的開銷,提升性能
2 減少jvm垃圾回收
單例的壞處:
1 對於有狀態的變量可能會造成線程安全問題,因爲只有一個實例,如果操作的是有狀態的全局變量,多個線程之間可能會操作同一個變量和對象導致線程不安全問題
多例的好處:
1 線程安全,每個請求過來都分配一個新的對象,裏面的所有東西屬性方法都是該線程獨享的
壞處:
1 資源開銷大,創建對象需要消耗性能
2 會產生大量的垃圾對象
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);
}