標籤:volatile 使用 ret 消極式載入 懶漢 stat pre code 類裝載
單例模式是用來保證這個類在運行期間只會被建立一個類執行個體,另外,單例模式提供了一個全域唯一訪問這個類執行個體的訪問點,就是getInstance方法。
對於單例模式而言,不管採用何種實現方式,它都只是關心類執行個體的建立問題,不關心具體的業務功能。
第一種方案:懶漢式
懶漢式的類的執行個體建立是在getInstance方法中,懶漢式是典型的時間換空間,也就是每次擷取執行個體都會進行判斷,看是否需要建立執行個體,浪費判斷的時間。當然,如果一直沒人使用的話,那就不會建立執行個體,則節約記憶體空間
package 單例模式;/** * 懶漢式 * @author Administrator * */public class Singleton1 { private static Singleton1 uniqueInstance = null; private Singleton1(){} public static synchronized Singleton1 getInstance(){ if(uniqueInstance == null){ uniqueInstance = new Singleton1(); } return uniqueInstance; } }
這種懶漢式不加同步,所以是線程不安全的,可以加上synchornized使得安全執行緒:
public static synchronized Singleton getInstance(){}
但是這樣會降低整個訪問的速度,而且每次都要判斷,可以使用“雙重檢查加鎖”使得即安全執行緒,又能使效能不受到很大的影響。
“雙重檢查加鎖”是指並不是每次進入getInstance方法都需要同步,而是先不同步,進入方法過後,先檢查執行個體是否存在,如果不存在才進入下面的同步塊,這是第一重檢查,進入同步塊過後,再次檢查執行個體是否存在,不過不存在,就在同步的情況下建立一個執行個體,這是第二重檢查。這樣一來,就只需要同步一次了,從而減少了多次在同步的情況下進行判斷所浪費的時間,實現如下:
package 單例模式;/** * 雙重加鎖懶漢式 * @author Administrator * */public class Singleton3 { private volatile static Singleton3 instance = null; private Singleton3(){} public static Singleton3 getInstance(){ if(instance == null){ synchronized (Singleton3.class) { if(instance == null){ instance = new Singleton3(); } } } return instance; }}
第二種方案:餓漢式
餓漢式是典型的空間換時間,當類載入的時候就會建立類執行個體,不管你用不用,先建立出來,然後每次電泳的時候,就不需要再判斷了,節省了已耗用時間,餓漢式是安全執行緒的
package 單例模式;/** * 餓漢式 * @author Administrator * */public class Singleton2 { private static Singleton2 uniqueInstance= new Singleton2(); private Singleton2(){} public static Singleton2 getInstance(){ return uniqueInstance; }}
Java中一種更好的單例實現方式:
上面兩種方案都有一定的缺陷,那麼有沒有一種方法既能夠實現消極式載入,又能夠實現安全執行緒呢?
要想實現安全執行緒,可以採用靜態初始化器的方式,它可以由JVM來保證線程的安全性,例如前面的餓漢式,但這樣一來,會浪費一定的空間。
如果有一種方法能夠讓類裝載的時候不去初始化對象,不就解決問題了嗎?一種可行的方法就是採用內部類,在這個內部類裡面去建立對象執行個體,這樣一來,只要不實用到這個類級內部類,就不會建立對象執行個體,從而同時實現消極式載入和安全執行緒。
實現如下:
package 單例模式;/** * 使用內部靜態類,安全執行緒且高效 * @author Administrator * */public class Singleton4 { private static class SingletonHolder{ private static Singleton4 instance = new Singleton4(); } private Singleton4(){ } public static Singleton4 getInstance(){ return SingletonHolder.instance; }}
PS:不久前去參加珍愛網的春招,java開發工程師的面試有道題問到安全執行緒且高效的單例模式,就可以採用內部類的方式實現,可惜當時不懂。
java單例模式的幾種實現