【Java設計模式】單例模式

單例設計模式實現

單例設計模式:某個類只能存在一個對象實例
設計要點:java

  • 一個私有構造函數(不能外面new,只能本身建立)
  • 一個私有靜態變量(確保只有一個實例)
  • 一個公共靜態函數(調用,用來返回實例對象)

餓漢式

天生線程安全,用得也比較多
先建立實例,由於比較餓,沒有延遲加載,若是好久沒用到這個實例,就會浪費系統資源。spring

靜態常量餓漢式

public class Singleton {
    static class Singleton{
        private Singleton(){}
        private final static Singleton instance = new Singleton();
        public static Singleton getInstance() {
            return instance;
        }
    }
}

靜態代碼塊餓漢式

public class Singleton {
    private Singleton() {
    }
    private static Singleton instance;
    static { // 在靜態代碼塊中,建立單例對象
        instance = new Singleton();
    }
    public static Singleton getInstance() {
        return instance;
    }
}

懶漢式

用的時候再建立實例,由於比較懶數據庫

線程不安全懶漢式

多線程下,一個線程進入了if判斷語句塊,還將來得及往下執行,另外一個線程也經過了這個判斷語句,這時便會產生多個實例。因此在多線程環境下不可以使用這種方式設計模式

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    //提供一個靜態的公有方法,當使用到該方法時,纔去建立實例
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

線程安全懶漢式

效率低,多線程時,每次都要進行上鎖安全

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    //加入同步處理的代碼,解決線程安全問題
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

雙重檢測懶漢式(推薦)

線程安全,懶加載,效率較高springboot

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

volatile:保證了變量的可見性,若是發生改變,其餘線程立馬可見
雙重檢查:
首次建立實例時,進入第二個if判斷後,還未建立實例,此時如有其餘線程進來,經過了第一個if判斷,而後由於有synchronized,被擋在了外面。
實例化代碼只執行一次,後面線程再次訪問時,在第一個if判斷時,就直接return實例了。多線程

靜態內部類

線程安全,推薦使用
靜態內部類方式在 Singleton 類被裝載時並不會當即實例化,而是在須要實例化時,調用 getInstance 方法,纔會裝載 SingletonInstance 類,從而完成 Singleton 的實例化.
類的靜態屬性只會在第一次加載類的時候初始化,因此在這裏,JVM 幫助咱們保證了線程的安全性,在類進行初始化時,別的線程是沒法進入的。
外部類被加載的時候,靜態內部類不會被加載,靜態代碼塊會被加載。函數

public class Singleton {
    private static volatile Singleton instance;
    //構造器私有化
    private Singleton() {}
    //寫一個靜態內部類,該類中有一個靜態屬性 Singleton
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    //提供一個靜態的公有方法,直接返回 
    SingletonInstance.INSTANCE
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

枚舉

線程安全,還能防止反射和反序列化從新建立新的對象,不能延時加載工具

enum Singleton {
    INSTANCE; //屬性
    public void sayOK() {
        System.out.println("ok");
    }
}

使用場景

須要頻繁的進行建立和銷燬的對象,好比:工具類對象,頻繁訪問數據庫或文件對象。this

JDK源碼Runtime類

餓漢式單例
RunTime表明一個運行環境。每一個JVM進程都是對應這一個Runtime實例,此實例是由JVM爲其實例化的。每一個 Java 應用程序都有一個 Runtime 類實例,使應用程序可以與其運行的環境相鏈接。

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }
     private Runtime() {}
}

Spring依賴注入Bean實例

雙重檢查懶漢單例

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

SpringBoot源碼中的單例

......

相關文章
相關標籤/搜索