簡單引入
單例設計模式作為最簡單,最常用的設計模式。一般是這兩中寫法,這兩種寫法教科書所謂的标準寫法,但是實際上存在不少問題。後面介紹标準寫法,以規避這些問題。
1.懶漢式:
/**
* 問題在于,當多線程工作的時候,如果有多個線程同時運作到if (instance ==
* null),都判斷為null,那麼兩個線程就各自會建立一個執行個體——這樣一來,就不是單例了。
*/
class Singleton {
private Singleton() {
};
private static Singleton s;
public static Singleton getInstance() {
if (s == null) {
s = new Singleton();
}
return s;
}
}
2.惡漢式
class Singleton {
private Singleton() {
}
private static Singleton singleton = new Singleton();
public static Singleton getInstance() {
return singleton;
}
}
标準寫法
改變懶漢式1.
(規避線程安全問題)加上 synchronized修飾方法即可
class Singleton {
private Singleton() {
};
private static Singleton s;
public static synchronized Singleton getInstance() {
if (s == null) {
s = new Singleton();
}
return s;
}
}
改變懶漢式2. 雙重檢查 Double-Check』寫法
1.第一個if 隻有instance為null的時候,才進入synchronized的代碼段——大大減少了幾率。
2.第二個if 是為了防止可能出現多個執行個體的情況。
class DoubleCheck {
private DoubleCheck() {
}
private static DoubleCheck dCheck;
public static DoubleCheck getInstance() {
if (dCheck == null) {
synchronized (DoubleCheck.class) {
if (dCheck == null) {
dCheck = new DoubleCheck();
}
}
}
return dCheck;
}
}
改變懶漢式2.之終極版 防止指令重排列 volatile
不知道原子操作,與指令重排的建議複習下
class DoubleCheck2 {
private DoubleCheck2() {
}
private static volatile DoubleCheck2 sCheck;
public static DoubleCheck2 getInstance() {
if (sCheck == null) {
synchronized (DoubleCheck2.class) {
if (sCheck == null) {
sCheck = new DoubleCheck2();
}
}
}
return sCheck;
}
}
1.惡漢式:
/*
* 缺點也就隻是餓漢式單例本身的缺點所在了——由于INSTANCE的初始化是在類加載時進行的,而類的加載是由ClassLoader來做的,
* 是以開發者本來對于它初始化的時機就很難去準确把握:
*
* 可能由于初始化的太早,造成資源的浪費 如果初始化本身依賴于一些其他資料,那麼也就很難保證其他資料會在它初始化之前準備好。
*/
class Singleton {
private Singleton() {
}
private static final Singleton singleton = new Singleton();
public static Singleton getInstance() {
return singleton;
}
}
由于靜态内部類實作
class innerSingleton {
private innerSingleton() {
}
private static class SingletonHolder {
private static final innerSingleton SINGLETON = new innerSingleton();
}
public static innerSingleton getInstance() {
return SingletonHolder.SINGLETON;
}
}