設計模式系列——單例模式

單例模式

  單例模式(Singleton)的定義:一個類只能有一個實例,並且這個實例由這個類創建。在軟件設計中,爲了節約空間、保證數據的一致性,許多類只能擁有一個實例,這種設計就採用單例模式。單例模式的實現方法是:1、使類的構造方法私有化;2、創建屬於此類類型的靜態成員對象;3、提供靜態方法獲取對象。

單例模式的實現

  常用的單例模式的實現方式有4種,其中包括懶漢式、餓漢式、枚舉實現、雙重檢測方式,下面進行介紹。

餓漢式

  該方式的特點是在加載類的時候就創建對象,此種方式是線程安全的。但是在類的創建過程複雜、繁瑣時,這種方式導致類的加載過於緩慢。

/**
 * 單例模式餓漢式
 */
public class Singleton {

    private static final Singleton instance = new Singleton() ;
    private Singleton(){}

    public static Singleton getInstance(){
    	try {
            Thread.sleep(3000); //模擬創建延遲
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return instance;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(()->{
            ints1 = Singleton.getInstance();
        });
        Thread thread2 = new Thread(()->{
            ints2 = Singleton.getInstance();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(ints1 == ints2);
        System.out.println(ints1);
        System.out.println(ints2);
    }

}
枚舉方式

  這種方式有點和餓漢式一樣,都是簡單實現,同時是線程安全的。

// 枚舉實現方式
public enum SingletonEnum {

    Instance();
    
    SingletonEnum getInstance(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Instance;
    }
}

//測試類
public class Singleton {
    private static SingletonEnum inst1;
    private static SingletonEnum inst2;

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(()->{
            inst1 = SingletonEnum.getInstance();
        });
        Thread thread2 = new Thread(()->{
            inst2 = SingletonEnum.getInstance();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(inst1 == inst2);
        System.out.println(inst1);
        System.out.println(inst2);
    }

}
懶漢式

  這種方式的特點是在需要第一次需要對象的時候加載類。爲了保證線程安全,對實例對象使用volatile關鍵字,同時在獲取實例對象的方法上使用synchronized關鍵字。這種方式的缺點是在方法上加鎖過於頻繁,其實只需要在第一次創建對象的時候需要將方法加鎖,而後面獲取對象的操作是不需要加鎖的,這樣會降低效率。

/**
 * 單例模式懶漢式
 */
public class Singleton {

    private static volatile Singleton instance = null;
    private static Singleton ints1;
    private static Singleton ints2;

    private Singleton(){}

    public static synchronized Singleton getInstance(){
    	try {
            Thread.sleep(3000); //模擬創建延遲
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(()->{
            ints1 = Singleton.getInstance();
        });
        Thread thread2 = new Thread(()->{
            ints2 = Singleton.getInstance();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(ints1 == ints2);
        System.out.println(ints1);
        System.out.println(ints2);
    }

}
雙重檢測方式

  這種方式是改造懶漢式創建方式,只在第一次創建時加鎖,後面獲取實例不用加鎖便能獲取對象,改善了獲取類的效率。

**
 * 單例模式雙重檢測方式
 */
public class Singleton {

    private static volatile Singleton instance = null;
    private static Singleton ints1;
    private static Singleton ints2;

    private Singleton(){}

    public static Singleton getInstance(){
       if(instance == null){
           synchronized (Singleton.class){
               if(instance == null){
                   try {
                       Thread.sleep(3000); //模擬創建延時
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   instance = new Singleton();
               }
           }
       }
        return instance;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(()->{
            ints1 = Singleton.getInstance();
        });
        Thread thread2 = new Thread(()->{
            ints2 = Singleton.getInstance();
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(ints1 == ints2);
        System.out.println(ints1);
        System.out.println(ints2);
    }

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