Java設計模式:單例模式

前言

之前對設計模式沒有太大感受。如今慢慢在工做中愈來愈感受設計模式的重要性,因此決定重頭來好好學習整理下經常使用的設計模式。
本文介紹的最初級的一個設計模式 單例模式java

模式說明

java中單例模式定義:一個類有且僅有一個實例,而且自行實例化向整個系統提供。設計模式

應用: 一個系統中多線程對一個文件進行操做,這個文件就須要保證只有一個實例,等等安全

餓漢式

說明:餓漢式意思就是不管系統需不須要使用該類的實例對象,先在類加載的時候建立好
優勢:實現簡單
缺點:容易形成內存的浪費多線程

經常使用餓漢式

該方式是在該類被加載的時候,就建立好了實例化對象。不容許其餘地方經過構造方法來建立對象,只能經過提供的指定公共方法來獲取惟一的對象。jvm

public class SingletonDemo1 {

    //static 確保在類加載的時候就會初始化該對象
    private final static SingletonDemo1 singleton = new SingletonDemo1();

    // 必須是私有構造方法,防止其餘地方經過構造方法來實例化對象
    private SingletonDemo1(){
    }

    // 是一個公共的靜態方法,用於對外提供惟一的對象
    public static SingletonDemo1 getInstance(){
        return singleton;
    }

}

枚舉

根據枚舉的特性,可使用枚舉來實現單例模式學習

public class SingletonDemo3 {

    // 不容許其餘地方經過構造方法進行實例化對象
    private SingletonDemo3(){}

    //對外提供可獲取惟一實例化對象的公共方法
    public static SingletonDemo3 getInstance(){
        return Singleton.SINGLETON.getInstance();
    }

    private enum Singleton{
        SINGLETON;

        private SingletonDemo3 singleton;

        Singleton(){
            singleton = new SingletonDemo3();
        }

        public SingletonDemo3 getInstance(){
            return singleton;
        }
    }

}

懶漢式

說明:懶漢式意思就是在系統第一次須要使用該類的實例對象時,再建立該類的實例對象。
優勢:不形成內存不必的浪費
缺點:實現相對較難.net

懶漢式-線程不安全

在有多線程使用的狀況下不要使用,不然可能會形成建立多個實例對象。通常建議不使用該種方式。線程

public class SingletonDemo1 {

    //static 確保在類加載的時候就會初始化該對象
    private static SingletonDemo1 singleton = null;

    // 必須是私有構造方法,防止其餘地方經過構造方法來實例化對象
    private SingletonDemo1(){
    }

    // 是一個公共的靜態方法,用於對外提供惟一的對象
    public static SingletonDemo1 getInstance(){
        if(singleton==null){
            singleton = new SingletonDemo1();
        }
        return singleton;
    }

}

懶漢式-線程安全-同步方法

因爲上面的方式,是在執行getInstance()方法時,多線程使用時可能出現建立多個對象的狀況。那能夠直接將該方法進行同步,保證任意時間,最可能是能一個線程使用該方法。設計

public class SingletonDemo2 {

    //static 確保在類加載的時候就會初始化該對象
    private static SingletonDemo2 singleton = null;

    // 必須是私有構造方法,防止其餘地方經過構造方法來實例化對象
    private SingletonDemo2(){
    }

    // 是一個公共的靜態方法,用於對外提供惟一的對象
    public static synchronized  SingletonDemo2 getInstance(){
        if(singleton==null){
            singleton = new SingletonDemo2();
        }
        return singleton;
    }

}

缺點:過重了,每一個線程在每次使用的時候,都須要進行同步,而實際上只是在第一次獲取該類的實例對象時須要同步,日後使用不須要同步。

懶漢式-線程安全-雙重鎖

該方式只會在未實例化對象時,才同步進行實例化對象。實例化後就不須要再進行同步了。

public class SingletonDemo2 {

    //static 確保在類加載的時候就會初始化該對象
    private static volatile SingletonDemo2 singleton = null;

    // 必須是私有構造方法,防止其餘地方經過構造方法來實例化對象
    private SingletonDemo2(){
    }

    // 是一個公共的靜態方法,用於對外提供惟一的對象
    public static SingletonDemo2 getInstance(){
        if(singleton==null){
            synchronized (SingletonDemo2.class){
                if(singleton==null) { //爲了防止多個線程進行實例化
                    singleton = new SingletonDemo2();
                }
            }
        }
        return singleton;
    }

}

有麼有注意到,使用了volatitle關鍵字,爲何要使用volatile關鍵字?
答:這裏使用了volatile一個重要的特性——禁止JVM指令重排序
singleton = new SingletonDemo2()的在jvm內存中會有三步,1)分配內存;2)初始化對象;3)將對象指向分配的內存。jvm在會在不改變最終執行結果的狀況下對指令進行重排序,即:可能執行順序是1->3->2,如果在執行執行3還未執行2時,其餘線程執行使用,則會報錯。
(參考:http://www.javashuo.com/article/p-plwggyio-cp.html

參考資料

http://www.javashuo.com/article/p-qjktkfot-ck.html
http://www.runoob.com/design-pattern/singleton-pattern.html
java實例化對象過程說明:http://www.javashuo.com/article/p-rtbvcfpv-ey.html

相關文章
相關標籤/搜索