單例的實現
1.單線程下的Lazy實現
public class Main {
private static Main instance = null;
private Main() {}
public static Main getInstance() {
if(null == instance) instance = new Main();
return instance;
}
}
2.針對1的多線程阻塞實現
就是改進了check-then-act的原子性問題
public class Main {
private static Main instance = null;
private Main() {}
public static Main getInstance() {
synchronized(Main.class) {
if(null == instance) instance = new Main();
}
return instance;
}
}
3.錯誤的雙重加鎖
public class Main {
private static Main instance = null;
private Main() {}
public static Main getInstance() {
if(null == instance) synchronized(Main.class) {
if(null == instance) instance = new Main(); // 問題出現在初始化
}
return instance;
}
}
注意可見性是正確的,錯誤在於初始化的重排序
上一篇文章已經寫了3個步驟,一個線程在判斷第一個if的時候可能另一個線程執行到第二個步驟就寫入引用了,這時返回的是默認值
4.正確的雙重加鎖
既然重排序有問題那當然要volatile
public class Main {
private static volatile Main instance = null;
private Main() {}
public static Main getInstance() {
if(null == instance) synchronized(Main.class) {
if(null == instance) instance = new Main();
}
return instance;
}
}
5.靜態內部類
利用class文件對於內部類的特性,實現上夠簡單
public class Main {
private static class InstanceHolder {
final static Main INSTANCE = new Main();
}
public static Main getInstance() {
return InstanceHolder.INSTANCE;
}
}
6.枚舉類
僅訪問Singleton本身不會使Singleton.INSTANCE初始化
public enum Singleton {
INSTANCE;
Singleton() {}
public void doSomething() {}
}
public class Main {
public static void main() {
new Thread() {
public void run() {
Singleton.INSTANCE.doSomething();
}
}.start();
}
}
懶漢?餓漢?
補充一下奇怪的術語:懶漢式、餓漢式
其中懶漢式就是帶Lazy加載的意思,比如1、2
而餓漢式我並不太清楚字面上的意思。。應該是指內存寬裕吧。。就是static直接返回的那種,顯然不如靜態內部類
public class Main {
private static Main instance = new Main();
private Main() {}
public static Main getInstance() { return instance; }
}
破壞單例模式
1.除了enum和靜態內部類,其它都可以被newInstance()拿到手
改進方法就是在構造方法創建保護null的判斷
2.還有一種反序列化的破壞方式(如果你的單例需要序列化)。。
解決方法是重寫readResolve()
方法,使得它在方法內直接返回instance