單例模式的編寫有多種方式,但是有些細節的地方容易被大家忽略,在這裏我簡單的向大家分享一下,如有不正確的地方,還望指正。
經典的單例模式有兩種方式一種是餓漢式,一種是懶漢式。
先來提一下餓漢式,這個是最簡單但是最不實用的。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
//餓漢式
public static SingleTone getInstance(){
single = new SingleTone();
return single;
}
}
下面是比較簡單的懶漢式編寫,主要是爲了保證創建的對象只有一個。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
//懶漢式
public static SingleTone getInstance(){
if(single==null){
single = new SingleTone();
}
return single;
}
}
這種懶漢式存在線程安全問題,所以需要加同步鎖,加同步鎖,則有兩種方式,一種是將synchronized加在方法上,另一種是將synchronized加在方法內。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
public synchronized static SingleTone getInstance(){
if(single==null){
single = new SingleTone();
}
return single;
}
}
但是,synchronized加在方法會使效率低,因爲鎖的範圍比較大,我們要向保證是單例的,其實主要是爲了保證single = new SingleTone();是線程安全的就行,所以在加鎖的時候,我們一般會將鎖加到方法裏面。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
public static SingleTone getInstance(){
if(single==null){
synchronized (SingleTone.class) {
single = new SingleTone();
}
}
return single;
}
}
將鎖加到裏面後又會有新的問題,如果兩個線程同時進入了getInstence()中後,並都判斷了single等於null,其中一個進入同步鎖中,另外一個在門口等待,當一個創建完對象後讓出鎖,另一個直接進去,這樣它就會又創建對象,所以更好的方式是加雙重鎖定,這種方式是效率高,並且安全。
public class SingleTone {
private SingleTone(){
}
private static SingleTone single = null;
public static SingleTone getInstance(){
if(single==null){
synchronized (SingleTone.class) {
if(single==null){
single = new SingleTone();
}
}
}
return single;
}
}