單例模式(Singleton Pattern):
Ensure a class has only one instance,and provide a global point of access to it
(確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例)
一、單例模式特點:
1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。
二、單例模式目的:
得到一個類只可創建一個對象(並提供一個訪問它的全局訪問點)
三、單例模式應用場景
配置文件、網絡令牌,Mybatis中創建sqlSession
三、單例模式的實現(如下代碼):
1、構造函數私有化,不允許外部直接創建對象(構造函數私有化的類不允許被繼承)
2、定義私有的靜態成員(唯一實例instance)
3、定義公有靜態方法(用於獲取實例)
a、餓漢模式
在類初始化時,已經自行實例化
餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以後不再改變,所以天生是線程安全的。
b、懶漢模式
Singleton通過將構造方法限定爲private避免了類在外部被實例化,在同一個虛擬機範圍內,Singleton的唯一實例
只能通過getInstance()方法訪問。
懶漢模式線程不安全,於是,我們找到下面三種方式的改變
(1)加同步(每次都要同步,會影響性能)
(2)雙重鎖形式,檢查鎖定
在getInstance中做了兩次null檢查,確保了只有第一次調用單例的時候纔會做同步,這樣也是線程安全的,
同時避免了每次都同步的性能損耗
(3)靜態內部類
利用了classloader的機制來保證初始化instance時只有一個線程,所以也是線程安全
因爲Java機制規定,內部類Holder只有在getInstance()方法第一次調用的時候纔會被加載(實現了lazy),
而且其加載過程是線程安全的(實現線程安全)。內部類加載的時候實例化一次instance。
測試
四、懶漢模式和餓漢模式的區別
1、餓漢就是類一旦加載,就把單例初始化完成,保證getInstance的時候,單例是已經存在的了,
而懶漢比較懶,只有當調用getInstance的時候,纔回去初始化這個單例
2、餓漢模式加載類時比較慢,但運行時獲取對象速度比較快,線程安全
懶漢模式加載類時比較快,但運行時獲取對象速度比較慢,線程不安全
補充:
一個類或者程序所提供的接口對於線程來說是原子操作,或者多個線程之間的切換不會導致該接口的執行結果
存在二義性,也就是說我們不用考慮同步的問題,那就是線程安全的。