簡(jiǎn)單介紹
單例模式是最簡(jiǎn)單的設(shè)計(jì)模式之一,提供了一種創(chuàng)建對(duì)象的方式,確保在整個(gè)系統(tǒng)中只有一個(gè)對(duì)象被創(chuàng)建.單例模式解決了頻繁創(chuàng)建重復(fù)對(duì)象的問(wèn)題節(jié)約資源,可以省略創(chuàng)建對(duì)象所需要花費(fèi)的時(shí)間,對(duì)于一些重量級(jí)對(duì)象而言這點(diǎn)是很重要的.并且因?yàn)椴恍枰l繁創(chuàng)建對(duì)象 GC 的壓力也會(huì)有所減輕.
單例模式的一些實(shí)現(xiàn)方式
通常來(lái)說(shuō)在 Java 中的單例模式分為餓漢式和懶漢式,而且單例類需要一個(gè) private 的構(gòu)造函數(shù)防止被其他代碼實(shí)例化.下面來(lái)具體說(shuō)一下java 中單例模式的實(shí)現(xiàn).
餓漢式
public class Singleton{
private static Singleton instance =new Singleton();
//私有化構(gòu)造方法
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
餓漢式的單例模式代碼簡(jiǎn)單,線程安全,通過(guò)classLoader機(jī)制保證了單例對(duì)象的唯一性 但是不能確保instance 是在調(diào)用getInstance()方法的時(shí)候生成的不能達(dá)到懶加載效果
懶漢式
public class Singleton{
private static Singleton instance;
private Singleton(){}
//加入 synchronize 保證線程安全
public synchronized static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
在獲取的時(shí)候創(chuàng)建實(shí)例可以達(dá)到延遲加載的效果并且加入了 synchronize 保證線程安全,但每次調(diào)用代碼的時(shí)候都要加鎖,性能比較低還有可能發(fā)生阻塞
DCL雙重校驗(yàn)鎖
public class Singleton{
//volatile防止指令重排序
private static volatile Singleton instance=null;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
//加入第二次校驗(yàn)
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
雙重校驗(yàn)鎖就是為了解決上述問(wèn)題而存在的,先檢查實(shí)例是否存在然后再去創(chuàng)建,可以不用每次調(diào)用方法都獲取同步鎖性能會(huì)有一些提升,減小的鎖的顆粒度.但是 java 對(duì)象的創(chuàng)建和賦值不是一步操作的,有可能先去賦值給中instance之后才去創(chuàng)建 Singleton 這時(shí)添加volatile關(guān)鍵字防止指令重排序解決了這個(gè)問(wèn)題.
靜態(tài)內(nèi)部類
public class Singleton{
private Singleton(){}
public static class SingleHoler{
public static final Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingleHoler.instance;
}
}
使用靜態(tài)內(nèi)部類時(shí),當(dāng)Singleton被創(chuàng)建的時(shí)候不會(huì)去加載SingleHoler,只有第一次調(diào)用getInstance()方法時(shí)才回去創(chuàng)建instance,加載SingleHoler將常量池中的符號(hào)引用替換成直接引用,這種方式不僅保證了線程安全而且可以達(dá)到延遲加載的效果.
最佳實(shí)踐
public enum Singleton{
INSTANCE;
public void print(){
System.out.println("快樂(lè)就完事了!");
}
}
這種方法在功能上與公有域方法相近结榄,但是它更加簡(jiǎn)潔呵萨,無(wú)償提供了序列化機(jī)制苛谷,絕對(duì)防止多次實(shí)例化灰嫉,即使是在面對(duì)復(fù)雜序列化或者反射攻擊的時(shí)候贴汪。雖然這種方法還沒(méi)有廣泛采用鹿寨,但是單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法庐氮。 --《Effective Java 中文版 第二版》
簡(jiǎn)單到不能再簡(jiǎn)單了啊.jvm 在加載枚舉類的時(shí)候會(huì)使用loadClass方法使用同步代碼塊解決線程安全問(wèn)題.使用 enum 的單例模式還能避免反序列化破壞單例并且不能被反射攻擊.