單例模式定義:
保證一個類只要一個實例,並提供一個訪問它的全局訪問點。
應用場景:
如下圖,一般我們都會配置一下配置參數在文件conf.properties中,應用程序線程在運行的時候會先加載解析配置文件,將文件內容保存到數據對象conf.java中。通過這種方式,線程就可以訪問配置內容了。
這種場景有個很明顯的問題,就是每個線程要訪問配置文件的時候,都需要創建加載conf.properties配置文件創建conf對象。然而加載文件是個很耗時的過程,創建多個conf對象也浪費系統內存。其實我們只需要創建一個conf對象就夠了。那麼如何創建一個全局的conf對象呢,很顯然使用單例模式。
創建單例對象
創建單例對象注意要點
在講如何創建單例對象之前,首選要講一下創建單例對象注意要點:
- 提供一個創建獲取對象的方法;
- 對象構造器使用private,不允許外部創建對象(枚舉類除外);
- 創建對象要線程安全;
- 獲取對象性能要高
創建單例對象
餓漢式
private static final SingletonPattern singleton =new SingletonPattern();
public static SingletonPattern getSingleton(){
return singleton;
}
餓漢式可以這樣理解,一個人已經很餓了,在幹活之前肯定要先喫飯了。對於應用程序來說,提供服務之前,就要先創建單例對象,調用方來獲取對象的時候直接返回創建好的對象,省去了創建對象的時間。
懶漢式
private static SingletonPattern singleton1;
public static synchronized SingletonPattern getSingleton1(){
if (singleton1==null){
return singleton1;
}
return singleton1;
}
懶漢式其實就是延遲加載,在需要的時候才創建。這種方式缺點是,每次獲取對象都要加同步鎖,性能很差。
雙重檢測
private static volatile SingletonPattern singleton2;
public static SingletonPattern getInstance2(){
if (singleton2 ==null){
synchronized (SingletonPattern.class){
if (singleton2==null){
singleton2=new SingletonPattern();
}
}
}
return singleton2;
}
這種方式在對象爲空的時候才加鎖,很好的解決了懶漢式帶來的問題。volatile 保證可見性有序性,防止其他線程獲取到還未初始化完成的對象。
靜態內部類
private static class SingletonUtil{
private static final SingletonPattern instance=new SingletonPattern();
}
private static SingletonPattern getSingleton3(){
return SingletonUtil.instance;
}
靜態內部類在訪問的時候纔會加載初始化,這種方式利用了靜態內部類的特性。
枚舉類
public enum SingletonEnum {
Singleton ;
private SingletonPattern singletonPattern=new SingletonPattern();
public SingletonPattern getSingletonPattern(){
return singletonPattern;
}
//獲取單例對象
SingletonPattern singletonPattern = SingletonEnum.Singleton.getSingletonPattern();
枚舉類特性是每個類成員是全局唯一的,可以利用這種特性創建單例對象。
利用緩存創建對象
定義一個hashMap對象,獲取對象之前先從hashMap中獲取,獲取不到就創建對象,然後把創建的對象放入hashmap中。
總結
創建單例對象要注意一下上述所說的注意要點,考慮各種創建方式的優缺點,結合自己業務場景,選擇合適的創建模式。