設計模式part3
單例模式
單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例
常見的單例模式可以分爲懶漢模式和餓漢模式
懶漢模式
懶漢模式是指在第一次調用的時候進行實例化
【java】
publicclass Singleton1 {
//私有的構造器可以在其他類中實例化被實例化
private Singleton1(){}
privatestatic Singleton1 singleton1 = null;
publicstatic Singleton1 getInstance(){
//第一次調用的時候實例化
if(singleton1==null){
singleton1 = new Singleton1();
}
returnsingleton1;
}
}
然而這種方式會存在線程安全的問題,在多線程併發的情況下會出現問題,於是可以有一下方式進行優化
一、【java】
publicstaticsynchronized Singleton1 getInstance(){
//第一次調用的時候實例化
if(singleton1==null){
singleton1 = new Singleton1();
}
returnsingleton1;
}
synchronized關鍵字鎖住的是這個對象,這樣的用法,在性能上會有所下降,因爲每次調用getInstance(),都要對對象上鎖,事實上,只有在第一次創建對象的時候需要加鎖,之後就不需要了,所以,這個地方需要改進。我們改成下面這個:
二、【java】
publicstatic Singleton1 getInstance() {
if (singleton1 == null) {
synchronized (singleton1) {
if (singleton1 == null) {
singleton1 = new Singleton1();
}
}
}
returnsingleton1;
}
似乎解決了之前提到的問題,將synchronized關鍵字加在了內部,也就是說當調用的時候是不需要加鎖的,只有在instance爲null,並創建對象的時候才需要加鎖,性能有一定的提升。但是,這樣的情況,還是有可能有問題的,看下面的情況:在Java指令中創建對象和賦值操作是分開進行的,也就是說instance= new Singleton();語句是分兩步執行的。但是JVM並不保證這兩個操作的先後順序,也就是說有可能JVM會爲新的Singleton實例分配空間,然後直接賦值給instance成員,然後再去初始化這個Singleton實例。這樣就可能出錯了
publicclass Singleton2 {
privatestaticclass SingletonFactory {
privatestaticfinal Singleton2 INSTANCE = new Singleton2();
}
private Singleton2 (){}
publicstaticfinal Singleton2 getInstance(){
return SingletonFactory.INSTANCE;
}
}
使用靜態內部類的方式,既實現了線程安全,又避免了同步帶來的性能影響。
餓漢模式
餓漢模式是指類初始化的時候就已經自行實例化了,天生就是線程安全的,不需要考慮線程安全的問題
publicclass Singleton3 {
private Singleton3(){}
privatestatic Singleton3 singleton3 = new Singleton3();
publicstatic Singleton3 getInstance(){
returnsingleton3;
}
}