單例是指一個類僅有一個例項,通過提供的方法來作為全域性的訪問點
實現例子如下public enum SingleTonEnum{
INSTANCE;
public static final SingleTonEnum getInstance(){
return INSTANCE;
}
}
複製程式碼
單例的優勢
- 對訪問物件的嚴格控制
- 不存在頻繁建立物件與物件GC帶來的消耗
單例多種實現方式對比
單例實現的最困難方式在於,如何才能保證“全域性”有且僅有一個實現,這裡的“全域性”則是針對不同的使用場景來做各自的應用即可。比如現在的應用都會部署到多臺機器上,每臺機器上都會有各自的jvm,那是否有必要保證所有的機器上都是同一個單例呢?或者可以僅僅把全侷限定在單個jvm呢?
一般來講,限定在jvm即可
當前一般的實現方式包括 使用列舉、雙重檢查、靜態內部類與餓漢式等等
餓漢式與靜態內部類相比,區別在於建立例項的時機,靜態內部類需要用到的時候才載入,餓漢式則相當於類載入的時候就建立,餓漢實現的例子比如jdk自帶的 Runtime 類,就是典型的應用
- 列舉:能夠自適應序列化、反射、無法克隆
- 雙重檢查:序列化、克隆業務場景需要特殊處理,當然,如果場景不需要支援序列化和克隆則是沒有問題,在反射上則是無法避免只實現單例
- 靜態內部類:序列化、克隆場景需要特殊處理,同樣不需要這些的場景也是沒有問題,另外和雙重檢查一樣,無法避免反射只有單例
歡迎找到反射實現單例的同學一起探討,個人驗證程式碼戳這裡
另外對於自定義類載入器,只要是遵循雙親載入模式的類載入器都能實現單例
實際上沒有用到自己的類載入器,實現相同的類載入器
各實現方式在不同場景下驗證單例方式詳情請戳這裡
spring中對bean設定 scope 為 singleton
spring可以在bean檔案中設定建立的bean指定使用域為"singleton"
<bean id="paxi" class="maokitty.paxi"></bean>
複製程式碼
這種方式它預設就是實現了一個singleton,它是針對每個IOC容器實現的
當然通過指定不同的id,它也會為成功的建立另一個例項,這也就是單例"全域性"所特定的範疇。spring singleton原始碼追蹤記錄請戳這裡
需要單例的一些場景
不希望其它地方再建立一個例項的場景