1.餓漢式單例
複製代碼代碼如下:
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton() { }
public static Singleton getInstance() {
return INSTANCE;
}
}
2、借助內部類別
屬於懶漢式單例,因為Java機制規定,內部類別SingletonHolder只有在getInstance()方法第一次呼叫的時候才會被載入(實作了lazy),而且其載入過程是執行緒安全的。內部類別載入的時候實例化一次instance。
複製代碼代碼如下:
public class Singleton {
private Singleton() { }
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
3.普通加鎖解決
複製代碼代碼如下:
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
雖然解決了線程安全性問題,但是每個線程調用getInstance都要加鎖,我們想要只在第一次調用getInstance時加鎖,請看下面的雙重檢測方案
4.雙重檢測,但要注意寫法
複製代碼代碼如下:
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
Singleton temp = instance;
if(temp == null) {
temp = new Singleton();
instance = temp
}
}
}
return instance;
}
}
由於指令重新排序問題,所以不可以直接寫成下面這樣:
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
但是如果instance實例變數用volatile修飾就可以了,volatile修飾的話就可以確保instance = new Singleton();對應的指令不會重排序,如下的單例程式碼也是執行緒安全的:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}