建立型模式之單例模式(2.1)
阿新 • • 發佈:2019-08-12
單例模式定義
在軟體系統中,一個類只有一個例項物件。(該類只提供一個取得例項的靜態方法)
推薦使用的三種單例模式
- DoubleCheck
- 靜態內部類
- 列舉
1.DoubleCheck 雙重檢查
特點:效率高,執行緒安全,延遲載入。
class DoubleCheck { private static volatile DoubleCheck instance; private DoubleCheck(){} public static DoubleCheck getInstance() { /* DoubleCheck如何實現?執行緒安全和效率提升 在多執行緒的環境下,假設執行緒A直接進入#2,例項化物件。 且例項化方法外用synchronized修飾,所以是執行緒安全的。 當執行緒A例項化物件結束,物件instance已經被建立,執行到#1的執行緒將會直接調到#3,返回instance 且DoubleCheck實現了延遲載入(new在方法裡) */ if(instance==null) //#1 { synchronized (DoubleCheck.class) //#2 { if(instance==null) { instance = new DoubleCheck(); //#3 } } } return instance; } } public class Operation { public static void main(String[] args) { DoubleCheck doubleCheck1 = DoubleCheck.getInstance(); DoubleCheck doubleCheck2 = DoubleCheck.getInstance(); System.out.println(doubleCheck1.hashCode()); System.out.println(doubleCheck2.hashCode()); } }
2.靜態內部類
特點:通過JVM類載入避免了執行緒安全問題,延遲載入,效率高。
class StaticClassInner { private StaticClassInner() {} /* 使用靜態內部類,實現了延遲載入 呼叫getInstance()方法時,才會載入StaticClassInnerInstance。 通過JVM類載入執行緒安全的機制,避免了執行緒不安全。 */ private static class StaticClassInnerInstance { private static final StaticClassInner INSTANCE = new StaticClassInner(); } public static StaticClassInner getInstance() { return StaticClassInnerInstance.INSTANCE; } } public class Operation { public static void main(String[] args) { StaticClassInner doubleCheck1 = StaticClassInner.getInstance(); StaticClassInner doubleCheck2 = StaticClassInner.getInstance(); System.out.println(doubleCheck1.hashCode()); System.out.println(doubleCheck2.hashCode()); } }
3.列舉
Effective Java作者Josh Bloch推薦。
enum Hq { INSTANCE; public void printf() { System.out.println("ins"); } } public class Operation { public static void main(String[] args) { Hq hq = Hq.INSTANCE; Hq hqq = Hq.INSTANCE; System.out.println(hq.hashCode()); System.out.println(hqq.hashCode()); } }
餓漢式的延遲載入問題(可用)
如果建立的物件一定會被使用,那麼可以忽略記憶體浪費的問題。
class SingleTom
{
private SingleTom()
{ }
/*
在靜態常量中例項化物件,無法實現延遲載入,如果物件未被使用,會造成記憶體浪費。(#1)
無執行緒安全問題
將例項化物件放於靜態程式碼塊中並無實際作用
*/
private final static SingleTom instance; // = new SingleTom();#1
static //#2
{
instance=new SingleTom();
}
public static SingleTom getInstance()
{
return instance;
}
}
public class Operation
{
public static void main(String[] args) {
SingleTom hq = SingleTom.getInstance();
SingleTom hqq = SingleTom.getInstance();
System.out.println(hq.hashCode());
System.out.println(hqq.hashCode());
}
}
懶漢式的執行緒安全問題(不可用)
class Singletom {
private static Singletom singleton;
private Singletom() {}
/*
執行緒不安全:
呼叫getInsyance()方法時,如果同時有多個執行緒同時進入到#1
就會建立多個例項物件
倘若在方法上加上syn關鍵字,執行緒同步問題解決,但效率大大降低
doublecheck大概就是在這種糾結下選擇用兩次if(singleton == null)來控制執行緒同步和效率問題
*/
public static /*synchronized*/ Singletom getInstance() {
if (singleton == null) { //#1
singleton = new Singletom();
}
return singleton;
}
}
public class Operation
{
public static void main(String[] args) {
Singletom hq = Singletom.getInstance();
Singletom hqq = Singletom.getInstance();
System.out.println(hq.hashCode());
System.out.println(hqq.hashCode());
}
}
參考文件:
單例模式的八種寫法比