單例模式

一. 單例模式的特點


  • 單例類只能有一個實例
  • 單例類必須創(chuàng)建自己唯一的實例
  • 單例類必須給其他對象提供這一實例

二. 餓漢 vs 懶漢

  • 餓漢:聲明實例引用時即實例化
  • 懶漢:靜態(tài)方法第一次被調(diào)用前不實例化,也即懶加載。對于創(chuàng)建實例代價大,且不定會使用時,使用懶加載可以減少開銷

三. 解決方案


1. 在多線程環(huán)境中能工作,但是效率不高,不建議面試采用(懶漢)

public class Singleton1 {
    private Singleton1 {}
    private static Singleton1 instance;
    public static synchronized Singleton1 getInstance() {
        if (instance == null) {
            instance = new Singleton1();
        }
        return instance;
    }
}
  • 優(yōu)點:線程安全,可確保正常使用(不考慮通過反射調(diào)用私有構(gòu)造方法),只有一個實例
  • 缺點:每次獲取實例都需要申請鎖,開銷大,效率低

2. 加同步鎖前后兩次判斷實例是否存在(懶漢)

public class Singleton2 {
    private Singleton2() {}
    private static Singleton2 instance;
    public static Singleton2 getInstance() {
        if(instance == null) {
            synchronized(Singleton2.class) {
                if (instance == null) {
                    instance = new Singleton2();
                }
            }
        }
        return instance;
    }
}
  • 優(yōu)點:不需要在每次調(diào)用時加鎖,效率比上一個高
  • 缺點:雖然使用了synchronized,但本質(zhì)上是線程不安全的

3. 雙重檢查(Double Check)下的懶漢

public class Singleton3 {
    private static volatile Singleton3 instance;
    private Singleton3() {}
    public static Singleton3 getInstance() {
        if (instance == null) {
            synchronized(Singleton3.class) {
                if (instance == null) {
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}
  • 優(yōu)點:使用了雙重檢查,避免了線程不安全,同時避免了不必要的鎖開銷
  • 缺點:無
  • 注意:使用volatile關(guān)鍵字的目的不是保證可見性(synchronized已經(jīng)保證了可見性),而是為了保證順序性。具體來說,instance = new Singleton3()不是原子操作,實際上被拆分為了三步:1) 分配內(nèi)存;2) 初始化對象;3) 將instance指向分配的對象內(nèi)存地址。 如果沒有volatile,可能會發(fā)生指令重排序,使得instance先指向內(nèi)存地址,而對象尚未初始化,其它線程直接使用instance引用進行對象操作時出錯。詳細原理可參見《雙重檢查鎖定與延遲初始化

4. 利用靜態(tài)變量(餓漢)

public class Singleton4 {
    private Singleton4() {}
    private static Singleton4 instance = new Singleton4();
    public static Singleton4 getInstance() {
        return instance;
    }
}
  • 優(yōu)點:實現(xiàn)簡單,無線程同步問題
  • 缺點:在類裝載時完成實例化。若該實例一直未被使用,則會造成資源浪費

5. 利用靜態(tài)代碼塊(餓漢)

public class Singleton5 {
    private static Singleton5 instance;
    private Singleton5() {}
    static {
        instance = new Singleton5();
    }
    public static Singleton5 getInstance() {
        return instance;
    }
}
  • 優(yōu)點:實現(xiàn)簡單,無線程同步問題
  • 缺點:在類裝載時完成實例化。若該實例一直未被使用,則會造成資源浪費

6. 實現(xiàn)按需創(chuàng)建實例(強烈推薦)(懶漢)

public class Singleton6 {
    private Singleton6() {}
    private static class Nested {
        private static Singleton6 instance = new Singleton6();
    }
    public static Singleton6 getInstance() {
        return Nested.instance;
    }
}
  • 優(yōu)點:無線程同步問題,實現(xiàn)了懶加載。因為只有調(diào)用getInstance()時才會裝載內(nèi)部類,才會創(chuàng)建實例。同時因為使用內(nèi)部類,先調(diào)用內(nèi)部類的線程會獲得類初始化鎖,從而保證內(nèi)部類的初始化(包括實例化它所引用的外部類對象)線程安全。即使內(nèi)部類創(chuàng)建外部類的實例Singleton6 instance = new Singleton6()發(fā)生指令重排也不會引起雙重檢查下的懶漢模式中提到的問題,因此無須使用volatile關(guān)鍵字。
  • 缺點:無

參考資料


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容