作圖網(wǎng)站做課程表紹興seo推廣公司
目錄
一、定義
二、應(yīng)用場景
三、6種實(shí)現(xiàn)方式
1、懶漢式,線程不安全。
2、懶漢式,線程安全
3、雙檢鎖/雙重校驗(yàn)鎖(DCL,即 double-checked locking)
4、靜態(tài)內(nèi)部類方式-------只適用于靜態(tài)域
5、餓漢式
6、枚舉
四、總結(jié)
一、定義
單例模式(Singleton Pattern)是 Java 中最簡單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。
單例模式涉及到一個單一的類,單例類只能自己創(chuàng)建唯一的一個實(shí)例,并提供了一個全局訪問點(diǎn)使所有其他對象獲取到類的唯一實(shí)例。
特點(diǎn):
- 唯一實(shí)例:確保類只有一個實(shí)例。
- 全局訪問點(diǎn):提供一個全局訪問點(diǎn)來獲取類的實(shí)例。
- 線程安全:在多線程環(huán)境中,確保實(shí)例的唯一性。
二、應(yīng)用場景
1、配置管理:應(yīng)用程序可能需要一個只初始化一次的配置管理器。
2、日志記錄:日志記錄器通常只需要一個實(shí)例,以避免日志信息的混亂。
3、性能優(yōu)化:某些對象的創(chuàng)建成本很高,使用單例模式可以避免重復(fù)創(chuàng)建。
三、6種實(shí)現(xiàn)方式
分類:
- 餓漢式:類加載就會導(dǎo)致該單實(shí)例對象被創(chuàng)建。
- ?懶漢式:類加載不會導(dǎo)致該單實(shí)例對象被創(chuàng)建,而是首次使用該對象時才會創(chuàng)建。
1、懶漢式,線程不安全。
在這種情況下,我們只有調(diào)用 getInstance 方法, instance 對象才會被創(chuàng)建。
在多線程情況下,很多線程都來請求獲取該對象,這樣就可能創(chuàng)建出多個對象,導(dǎo)致線程不安全。
/*** 懶漢式 線程不安全*/
public class SingletonLazy {//定義一個私有構(gòu)造方法private SingletonLazy(){}//創(chuàng)建該類對象private static SingletonLazy instance;//對外提供靜態(tài)方法獲取該對象public static SingletonLazy getInstance(){if(instance==null){instance = new SingletonLazy();}return instance;}
}
2、懶漢式,線程安全
由于上述會出現(xiàn)線程不安全問題,所以我們通過加同步鎖,保證每次只有一個線程可以對當(dāng)前對象進(jìn)行操作,確保了線程安全。但加鎖會影響效率。
/*** 懶漢式 線程安全*/
public class SingletonLazy {//定義一個私有構(gòu)造方法private SingletonLazy(){}//創(chuàng)建該類對象private static SingletonLazy instance;//對外提供靜態(tài)方法獲取該對象 , 加鎖public static synchronized SingletonLazy getInstance(){if(instance==null){instance = new SingletonLazy();}return instance;}
}
3、雙檢鎖/雙重校驗(yàn)鎖(DCL,即 double-checked locking)
我們使用?volatile 關(guān)鍵字, volatile 關(guān)鍵字可以保證可見性和有序性,這個關(guān)鍵字禁止了對當(dāng)前修飾的變量上下文重排序。保證了方法的可靠性。采用雙鎖機(jī)制,安全且在多線程情況下能保持高性能。
進(jìn)行二次判斷的原因:
假設(shè)有兩個線程a,b,他們都去請求我們單例模式下類的實(shí)例,當(dāng)?shù)谝粋€判斷的時候,兩個線程都會進(jìn)入判斷代碼塊中進(jìn)行鎖的搶占,最終a搶占到了鎖,那么b只能在加鎖的代碼塊外部進(jìn)行等候。這個時候a創(chuàng)建了對象的實(shí)例,完成功能后歸還了鎖,這個時候線程b馬上搶占到了鎖,然后進(jìn)入內(nèi)部代碼塊。假如沒有第二次判斷的話,線程a就會再次創(chuàng)建一個新的對象,導(dǎo)致線程不安全。所以,要在這里再加一次判斷。
/*** 懶漢式 雙重校驗(yàn)鎖*/
public class SingletonLazy {//定義一個私有構(gòu)造方法private SingletonLazy(){}//創(chuàng)建該類對象private volatile static SingletonLazy instance;//對外提供靜態(tài)方法獲取該對象 , 加雙重鎖public static SingletonLazy getInstance(){if(instance==null){synchronized (instance.getClass()){if(instance == null){instance = new SingletonLazy();}}}return instance;}
}
4、靜態(tài)內(nèi)部類方式-------只適用于靜態(tài)域
靜態(tài)內(nèi)部類單例模式中實(shí)例由內(nèi)部類創(chuàng)建,由于 JVM 在加載外部類的過程中, 是不會加載靜態(tài)內(nèi)部類的,只有內(nèi)部類的屬性/方法被調(diào)用時才會被加載,并初始化其靜態(tài)屬性。靜態(tài)屬性由于被 static 修飾,保證只被實(shí)例化一次,并且嚴(yán)格保證實(shí)例化順序。
/*** 靜態(tài)內(nèi)部類方式*/
public class SingletonLazy {//私有構(gòu)造方法private SingletonLazy() {}//定義靜態(tài)類private static class SingletonHolder {//靜態(tài)方法private static final SingletonLazy INSTANCE = new SingletonLazy();}//對外提供靜態(tài)方法獲取該對象public static SingletonLazy getInstance() {return SingletonHolder.INSTANCE;}
}
5、餓漢式
它基于 classloader 機(jī)制避免了多線程的同步問題,instance 在類裝載時就實(shí)例化。
/*** 餓漢式*/
public class SingletonEhan {//私有構(gòu)造方法private SingletonEhan(){}//創(chuàng)建并實(shí)例化該類對象private static SingletonEhan instance = new SingletonEhan();//對外提供靜態(tài)方法獲取該對象public static SingletonEhan getInstance(){return instance;}
}
6、枚舉
這種實(shí)現(xiàn)方式還沒有被廣泛采用,但這是實(shí)現(xiàn)單例模式的最佳方法。它更簡潔,自動支持序列化機(jī)制,絕對防止多次實(shí)例化。
public enum Singleton { INSTANCE; public void whateverMethod() { }
}
四、總結(jié)
一般情況下,使用第5種餓漢式。