8-1種單例模式

單例模式

所謂的單例模式就是採取一定的方法保證整個的軟件系統中,對某個了類只能存在一個對象實例, 並且該類只提供一個取得其對象的實例方法(靜態方法). 比如Hibernate的SessionFactory,它充當數據存儲源的代理,並且負責創建Session對象. SessionFactory並不是輕量級的,一般情況下,一個項目通常只需要一個SessionFactory就夠,這是就會使用到單例模式

單例設計模式有八種方式: 五類

1)餓漢式(靜態常量) ​ 2)餓漢式(靜態代碼塊)

3)懶漢式(線程不安全) ​ 4)懶漢式(線程安全,同步方法) ​ 5)懶漢式(線程安全,同步代碼塊)

6)雙重檢查 ​ 7)靜態內部類 ​ 8)枚舉

1)餓漢式(靜態常量) 應用實例

步驟如下:

1.構造器私有化 (防止通過new來創建實例)

2.類的內部創建對象

3.向外暴露一個靜態的公共方法 getInstance

4.代碼實現

​
public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1);   //true  
    }
}
​
//餓漢式(靜態變量)
class Singleton {
    //        1.使用構造器私有化
    private Singleton() {
    }
​
    //        2.本類內部創建對象實例  類加載時創建對象實例
    private final static Singleton instance = new Singleton();
​
    //        3.提供一個公有的靜態方法,返回實例對象
    public static Singleton getInstance() {
        return instance;
    }
}
​

優缺點說明:

1)優點:這種方法簡單,就是在類裝載的時候就完成實例化.避免了線程的同步問題.

2)缺點:在類加載的時候就完成了實例化,沒有達到Lazy Loading的效果.如果從始至終沒有使用過這個實例,就會造成內存浪費

3)這種方式基於classLoader機制避免了多線程同步的問題,不過,instance在類裝載時就實例化,在單例模式中大多數都是調用getInstance方法,但是導致類裝載的原因有很多種,因此不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化instance就沒有達到Lazy loading的效果

4)結論:這種模式可用,可能造成內存浪費

2)餓漢式(靜態代碼塊)

/**
 * 將靜態代碼塊中創建單例對象
 *
 * 優缺點說明:
 *      1)這種方和上面的方式其實類似,只不過將類的實例化過程放在了靜態代碼塊中,
 *      也是類裝載的時候,就執行靜態代碼塊中 的代碼,初始化類的實例,優越點和上面是一樣的
 *      2)結論:這種單例模式可用,但是會造成內存浪費
 *
 */
        ....
         private  static Singleton instance;
​
    static {
​
        //在靜態代碼塊中創建單例對象
        instance=new Singleton();
    }   
        ......

3)懶漢式(線程不安全的)

public class SingletonDemo3 {
    public static void main(String[] args) {
        System.out.println("懶漢式1,線程不安全-----");
        Singleton instance = Singleton.getInstance();     //爲空 直接返回
        Singleton instance1 = Singleton.getInstance();  //2.不爲空 直接返回
        System.out.println(instance == instance1);   //true
​
    }
}
​
class Singleton {
    private static Singleton instance;
​
    private Singleton() {
    }
​
    //提供一個靜態的公有方法,使用到getInstance時纔會創建instance
    //即是懶漢式
    public static Singleton getInstance() {
    //線程不安全的-----潛在的風險
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

優缺點聲明:

1)起到了懶加載的效果,但是隻能在單線程下使用

2)如果在多線程下,一個線程進入了if(Singleton==null)判斷語句塊,還未往下執行,另一個線程也通過這個判斷語句,這時會產生多個實例.所以在多線程環境下不可使用這種方式

3)結論:在實際開發中,不要使用這種方式.

4)懶漢式(線程安全,同步方法)

 ...........
 //提供一個靜態的公有方法,加入同步處理的代碼,解決線程安全問題
    //加一個關鍵字 synchronized  線程安全
    public static  synchronized  Singleton getInstance() {
​
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
.............

優缺點說明:

1)解決了線程不安全問題

2)效率太低,每個線程在想獲得類的實例的時候,執行getInstance()方法都要進行同步,而其實這個方法只執行一次代碼就夠了,後面的需要直接return就行了

3)結論:實際開發中,不推薦使用

5)懶漢式(線程安全,同步代碼塊)-----》線程安全都沒有解決

class Singleton{
    private static Singleton instance;
    private Singleton{}
    public static Singleton getInstance(){
        if(instance==null){
            synchronized (Singleton.class){
                instance=new  Singleton();
            }
            
        }
        return instance;
            
    }
}

優缺點說明:

1).這種方式,本意是想對第四種實現方法的改進,因爲前面同步方法的效率太低,更改爲同步實例化的代碼塊

2).但是這種方法並不能起到線程同步的作用。和第三種實現方式遇到的 情形一致,假如一個線程進入了if(singleton==null)判斷語句塊,還未來來得及往下執行,另一個線程也通過這個判斷語句,這便會產生多個實例

3).在實際的開發中,不能使用這種方式。

6)雙重檢查---》延遲加載,效率較高

public class DoubleCheck {
    public static void main(String[] args) {
        System.out.println("雙重檢查");
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance==instance2);
    }
}
    //雙重檢查
    class Singleton{
        private static  volatile  Singleton  instance;
​
        private Singleton() {
        }
        //提供一個靜態公有方法,加入雙重檢查代碼,解決線程安全問題,同時解決了懶加載問題
        //同時保證了效率,推薦使用
​
        public  static  synchronized  Singleton getInstance() {
            if (instance == null) {
                        synchronized (Singleton.class){
                            if (instance==null){
                                instance=new Singleton();
                            }
                        }
            }
            return  instance;
        }
​
}

優缺點說明:

1)Double-check 概念是多線程開發中常使用到的,如代碼中所示,我們判斷了兩次if(singleton==null)檢查,這樣就可以保證線程安全了

2)這樣,實例化代碼只執行一次,後面再次訪問時,判斷if(singleton==null),直接return實例化對象;

3)延遲加載,效率較高

4)結論:在實際開發中,推薦使用這種單例設計模式

7)枚舉

public class SingletonDemo{
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance1 = Singleton.INSTANCE;
        System.out.println(instance==instance1);
        instance.sayOk();
    }
}
enum Singleton{
        INSTANCE;   //一個屬性
        public   void   sayOk(){
            System.out.println("ok(~o ̄3 ̄)~");
        }
}

優缺點說明:

1)這藉助jdk1.5中添加的枚舉來實現單例模式,不僅能避免多線程問題,而且還能防止反序列化來創建對象的問題

2)這種方式是 Effective java作者Josh Bloch提倡創建單例模式的方式

3)結論:推薦使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章