單例模式Singleton

單例模式定義

確保某個類只有一個實例,並且自行實例化並向整個系統提供這個實例。java

單例模式類圖

類圖說明

  • Client:高層客戶類
  • Singleton:單例類

實現單例模式的要點

  • 構造函數不對外開放,通常爲Private
  • 經過一個靜態方法或枚舉返回單例類對象
  • 確保單例類的對象有且只有一個,尤爲在多線程環境下
  • 確保單例類對象在反序列化時不會從新構建對象

單例模式的實現方式

  • 餓漢:在聲明時就初始化
    /** 
     * 餓漢單例 
     */
    public class MySingleton {
        // 餓漢單例,在聲明時就初始化
        private static MySingleton ourInstance = new MySingleton();
    
        public static MySingleton getInstance() {
            return ourInstance;
        }
    
        private MySingleton() {
        }
    }
  • 懶漢:只有在使用時纔會實例化,在必定程度上節省了資源;缺點是第一次加載時須要及時進行實例化,反應稍慢,最大的問題是每次調用getInstance都要進行同步,形成沒必要要的同步開銷。這種模式通常不建議採用。
    /**
     * 懶漢單例
     */
    public class MySingleton {
        private static MySingleton ourInstance;
        
        public static synchronized MySingleton getInstance() {
            // 懶漢單例,只有在使用纔會實例化
            if (ourInstance == null) {
                ourInstance = new MySingleton();
            }
            return ourInstance;
        }
    
        private MySingleton() {
        }
    }
  • DCL:Double Check Lock。優勢是既可以在須要時實例化單例,又能保證線程安全,且單例對象初始化後調用getInstance不進行同步鎖。
    /**
     * Double Check Lock(DCL)
     */
    public class MySingleton {
        private static MySingleton ourInstance = null;
    
        private MySingleton() {};
    
        public static MySingleton getInstance() {
            // 避免沒必要要的同步
            if (ourInstance == null) {
                synchronized (MySingleton.class) {
                    // 建立實例
                    if (ourInstance == null) {
                        ourInstance = new MySingleton();
                    }
                }
            }
            return ourInstance;
        }
    }
  • 靜態內部類:當第一次加載Singleton類時並不會初始化,只有在第一次調用時纔會初始化。所以,第一次調用getInstance方法會致使虛擬機加載SingleHolder類,這種方式不只可以確保線程安全,也能保證單例對象的惟一性,同時也延遲了單例實例化,因此這是推薦使用的單例模式實現方式
    /**
     * 靜態內部類單例模式
     */
    public class MySingleton {
    
        private MySingleton() {};
    
        public static MySingleton getInstance() {
            return SingletonHolder.ourInstance;
        }
    
        /**
         * 靜態內部類
         */
        private static class SingletonHolder {
            private static MySingleton ourInstance = new MySingleton();
        }
    }
  • 枚舉單例:枚舉單例是線程安全的,而且在任何狀況下它都是一個單例。且沒法經過反序列化獲得對象。
    /**
     * 枚舉單例
     */
    public enum SingletonEnum {
        INSTANCE;
        public void dosomething() {
            System.out.println("do sth.");
        }
    }
  • 使用容器實現單例
    /**
     * 使用容器實現單例模式
     */
    public class SingletonManager {
        private static Map<String, Object> objMap = new HashMap<>();
    
        private SingletonManager() {}
    
        public static void registerService(String key, Object instance) {
            if (!objMap.containsKey(key)) {
                objMap.put(key, instance);
            }
        }
    
        public static Object getService(String key) {
            return objMap.get(key);
        }
    }

Android中的應用:

getSystemService 經過容器實現單例 安全

http://www.javashuo.com/article/p-zctqbwua-ed.html多線程

相關文章
相關標籤/搜索