設計模式之單例模式(創建型)
前言
本博客介紹一種創建型模式:單例模式
這是一種比較容易理解的設計模式,可以理解為創建對象的一種很好的做法。可以盡量避免創建過多的對象,給JVM造成很大的負載。
應用場景
單例模式的一些應用場景:
1、比如數據連接類,這是需要經常調用的
2、網站訪問量統計的服務類,需要多次調用
3、導出導入Excel表,一些業務復雜的系統需要多次調用
...
總結起來就是需要經常調用的通用類,我們可以用單例模式進行很好的設計。
編程思想
單例模式涉及了兩種重要的編程思想:懶加載思想和緩存思想
緩存思想:
private static Singleton instance = null;//先放內存緩存 public static Singleton getInstance() { if (instance == null) {//內存加載不到,創建對象 instance = new Singleton(); } return instance;//內存緩存有,直接調用 }
懶加載思想:
下面例子就是懶加載的簡單應用,創建一個對象都是需要用的時候實例,盡量不要在加載類的時候就實例了,這種方法可以很好的避免給JVM增加負載。這是一種很好的編程習慣。
public static Singleton getInstance() {
if (instance == null) {//對象需要用時才實例
instance = new Singleton();
}
return instance;
}
單例模式實例
下面介紹幾種常用的單例模式實例
1、懶漢模式
這是一種線程不安全,懶加載的方式
public class Singleton { private static Singleton instance; //定義private構造函數,使類不可以被實例 private Singleton (){} /** * 懶漢模式,線程不安全,懶加載 * @return */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
上面例子線程不安全,要線程安全可以加個同步鎖,不過加了同步鎖性能又不好了,加載慢
public class Singleton { private static Singleton instance; //定義private構造函數,使類不可以被實例 private Singleton (){} /** * 懶漢模式,線程安全,懶加載 * @return */ public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
2、餓漢模式
下面介紹一下單例模式的另外一種實現方式,餓漢模式
其實現原理就是在類內部全局new一個對象,利用Java虛擬機的類加載機制,保證了線程安全,不過很明顯,一創建了,就實例了單例類,會給JVM增加負載
public class Singleton {
//定義private構造函數,使類不可以被實例
private Singleton (){}
//加載類的時候,利用JVM的類加載機制創建對象,保證了線程安全,但是效率不好
private static Singleton instance = new Singleton();
/**
* 餓漢模式,線程安全,非懶加載
* @return
*/
public static Singleton getInstance() {
return instance;
}
}
3、雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)
下面介紹一種雙檢鎖的實現方式,這種方式看起來稍稍比較復雜了點,不過可以實現線程安全,同時雙檢鎖的方式可以保證性能比較高
public class Singleton {
//定義private構造函數,使類不可以被實例
private Singleton (){}
private volatile static Singleton instance;
/**
* 雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)線程安全,懶加載
* @return
*/
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
4、登記式/內部類
下面用內部類的方式來實現單例模式,這種方式可以和餓漢模式來對比一下
這種方式和剛才介紹的餓漢模式類似,不過區別就是做到了懶加載,我們可以分析例子。方法就是在單例類裏加個內部類,這樣做就不會像餓漢模式一樣,單例類一加載就實例對象。當調用getInstance方法的時候,才會調用,創建對象。這樣就做到了懶加載,同時也是利用JVM保證了線程安全
public class Singleton {
//定義private構造函數,使類不可以被實例
private Singleton (){}
public static class SingletonHolder{
private final static Singleton INSTANCE = new Singleton();
}
/**
* 登記式/靜態內部類,線程安全,懶加載
* @return
*/
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
5、枚舉模式
這種方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不僅能避免多線程同步問題,而且還自動支持序列化機制,防止反序列化重新創建新的對象,絕對防止多次實例化。不過,由於 JDK1.5 之後才加入 enum 特性,用這種方式寫不免讓人感覺生疏,在實際工作中,也很少用。
/**
* 枚舉方式
*/
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
設計模式之單例模式(創建型)