單例設計模式:某個類只能存在一個對象實例
設計要點:java
天生線程安全,用得也比較多
先建立實例,由於比較餓,沒有延遲加載,若是好久沒用到這個實例,就會浪費系統資源。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
餓漢式單例
RunTime表明一個運行環境。每一個JVM進程都是對應這一個Runtime實例,此實例是由JVM爲其實例化的。每一個 Java 應用程序都有一個 Runtime 類實例,使應用程序可以與其運行的環境相鏈接。
public class Runtime { private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime() { return currentRuntime; } private Runtime() {} }
雙重檢查懶漢單例
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); }
......