Singleton是一種創(chuàng)建型模式甚淡,指某個類采用Singleton模式坦袍,則在這個類被創(chuàng)建后嚷炉,只可能產生一個實例供外部訪問渊啰,并且提供一個全局的訪問點。
核心知識點如下:
(1) 將采用單例設計模式的類的構造方法私有化(采用private修飾)申屹。
(2) 在其內部產生該類的實例化對象虽抄,并將其封裝成private static類型走搁。
(3) 定義一個靜態(tài)方法返回該類的實例独柑。
/*** 方法一
* 單例模式的實現(xiàn):餓漢式,線程安全 但效率比較低*/
public class SingletonTest {
// 定義一個私有的構造方法
private SingletonTest() {? ? ? }
// 將自身的實例對象設置為一個屬性,并加上Static和final修飾符
private static final SingletonTest instance = new SingletonTest();
// 靜態(tài)方法返回該類的實例
public static SingletonTest getInstancei() {
? ? returninstance;
? ? ?}
}
方法一就是傳說的中的餓漢模式
優(yōu)點是:寫起來比較簡單迈窟,而且不存在多線程同步問題,避免了synchronized所造成的性能問題忌栅;
缺點是:當類SingletonTest被加載的時候车酣,會初始化static的instance,靜態(tài)變量被創(chuàng)建并分配內存空間索绪,從這以后湖员,這個static的instance對象便一直占著這段內存(即便你還沒有用到這個實例),當類被卸載時瑞驱,靜態(tài)變量被摧毀娘摔,并釋放所占有的內存,因此在某些特定條件下會耗費內存唤反。
/***方法二
* 單例模式的實現(xiàn):飽漢式,非線程安全**/
publicclassSingletonTest {
// 定義私有構造方法(防止通過 new SingletonTest()去實例化)
privateSingletonTest() {? ? ? }
// 定義一個SingletonTest類型的變量(不初始化凳寺,注意這里沒有使用final關鍵字)
private static ? SingletonTest instance;
// 定義一個靜態(tài)的方法(調用時再初始化SingletonTest,但是多線程訪問時彤侍,可能造成重復初始化問題)public static ?SingletonTest getInstance() {
? ? ? if(instance ==null) ? ?instance=newSingletonTest();
? ? ?return instance;
? ? ? ? ?}
}
方法二就是傳說的中的飽漢模式
優(yōu)點是:寫起來比較簡單肠缨,當類SingletonTest被加載的時候,靜態(tài)變量static的instance未被創(chuàng)建并分配內存空間盏阶,當getInstance方法第一次被調用時晒奕,初始化instance變量,并分配內存名斟,因此在某些特定條件下會節(jié)約了內存脑慧;
缺點是:并發(fā)環(huán)境下很可能出現(xiàn)多個SingletonTest實例。
/***方法三
* 單例模式的實現(xiàn):飽漢式,線程安全簡單實現(xiàn)**/
public ?class ?SingletonTest {
//定義私有構造方法(防止通過 new SingletonTest()去實例化)
privateSingletonTest() {? ? ? }
//定義一個SingletonTest類型的變量(不初始化砰盐,注意這里沒有使用final關鍵字)
private ?static ?SingletonTest instance;
//定義一個靜態(tài)的方法(調用時再初始化SingletonTest闷袒,使用synchronized 避免多線程訪問時,可能造成重的復初始化問題)
public static synchronized SingletonTest getInstance() {
?if(instance ==null) instance=newSingletonTest();
? ?return instance;
? ? ?}
}
方法三為方法二的簡單優(yōu)化
優(yōu)點是:使用synchronized關鍵字避免多線程訪問時楞卡,出現(xiàn)多個SingletonTest實例霜运。
缺點是:同步方法頻繁調用時,效率略低蒋腮。
/*** 方法四
* 單例模式最優(yōu)方案
* 線程安全? 并且效率高**/
public class ?SingletonTest {
// 定義一個私有構造方法
?private ? SingletonTest() {
? }
? //定義一個靜態(tài)私有變量(不初始化淘捡,不使用final關鍵字,使用volatile保證了多線程訪問時instance變量的可見性池摧,避免了instance初始化時其他變量屬性還沒賦值完時焦除,被另外線程調用)
private ?static volatile ?SingletonTest instance;
//定義一個共有的靜態(tài)方法,返回該類型實例
public ?static ? SingletonTest getIstance() {
// 對象實例化時與否判斷(不使用同步代碼塊作彤,instance不等于null時膘魄,直接返回對象乌逐,提高運行效率)if(instance ==null) {
//同步代碼塊(對象未初始化時,使用同步代碼塊创葡,保證多線程訪問時對象在第一次創(chuàng)建后浙踢,不再重復被創(chuàng)建)
synchronized(SingletonTest.class) {
//未初始化,則初始instance變量
? ? ? ? ? ? ? if(instance ==null) {
? ? ? ? ? ? ? ? ? instance=newSingletonTest();
? ? ? ? ? ? ? ? ? }
? ? ?}
? ?}
? ? return instance;
? ?}
}
方法四為單例模式的最佳實現(xiàn)灿渴。內存占用地洛波,效率高,線程安全骚露,多線程操作原子性蹬挤。
(事實上,可以通過Java反射機制來實例化private類型的構造方法棘幸,此時基本上會使所有的Java單例實現(xiàn)失效焰扳。本帖不討論反射情況下問題,默認無反射误续,也是常見的面試已經應用場景)