什麼是單例模式? html
顧名思義,就是隻有一個實例,也就是說一個應用程序中只有一個實例對象.java
既然一個系統,一個應用程序中只有一個實例,那麼也就說明了若是操做這一個對象,必然涉及到共享資源,涉及到資源分配問題,資源競爭等問題. 數據庫
那麼咱們的應用場景是什麼呢?設計模式
1. 網站的在線人數. 網站的在線人數在某一個時刻,全部人看到的是同樣的, 是這個網站這個時刻,全部用戶所共享的.安全
2. 池化技術. 好比數據庫的鏈接池. 每一個數據庫的可支持的鏈接數量是有限,並且鏈接對象建立和銷燬也是比較耗內存的. 經過一個統一的入口去控制,能夠保證對數據庫的壓力在可控的範圍內,同是也能夠保證出具庫鏈接的持續使用.併發
3. 配置中心. 一個應用程序針對經過一個配置文件的加載只須要加載一次便可,不須要屢次加載.網站
其實以上只是一些常見的應用場景,固然單例模式的應用場景也遠不止於此.this
本文參考的博客地址爲:http://www.javashuo.com/article/p-fcozwjup-gn.html線程
參考的博客的寫的很不錯, 若是想了解更多,能夠去看看這篇參考的博客設計
接下來咱們來看一下常見的實現方式,以及其中的對比.
餓漢式,即直接初始化好,使用的時候直接調用便可.
package com.cbl.design.singletondesign; public class HungrySingleton { private static final HungrySingleton singleton = new HungrySingleton(); //限制外部產生HungrySingleton對象 private HungrySingleton(){ } //向外提供獲取示例的靜態方法 public static HungrySingleton getInstance() { return singleton; } }
懶漢式, 顧名思義,就是懶,須要的時候再去初始化
package com.cbl.design.singletondesign; public class LazySingleton { private static volatile LazySingleton singleton = null; private LazySingleton() { } public static LazySingleton getSingleton() { //不用每次獲取對象都強制加鎖,爲了提高了效率 if (singleton == null) { synchronized (LazySingleton.class) { if (singleton == null) { singleton = new LazySingleton(); } } } return singleton; } }
靜態內部類的方式
package com.cbl.design.singletondesign; public class StaticInnerSingleton { /** * 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例 * 沒有綁定關係,並且只有被調用到時纔會裝載,從而實現了延遲加載。 */ private static class Singleton2Holder { /** * 靜態初始化器,由JVM來保證線程安全 */ private static StaticInnerSingleton singleton = new StaticInnerSingleton(); } private StaticInnerSingleton() { //System.out.println("singleton2 private construct method called"); } public static StaticInnerSingleton getSingleton() { //System.out.println("singleton2 getSingleton method called"); return Singleton2Holder.singleton; } private String name; public void desc() { //System.out.println("singleton2 desc method called"); } }
還有一種實現方式是依賴於枚舉, 咱們知道枚舉中的對象是實例化好的,並且枚舉天生要求枚舉類的構造器必須私有,並且自己仍是被final 修飾的, 不可被繼承
package com.cbl.design.singletondesign; public enum EnumSingleton { INSTANCE; public String getDesc() { return "desc"; } public static void process() { System.out.println("static process method"); } private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
以上是4中常見的構造單例模式的四種線程安全的構造單例的設計模式.網上可能還有其他的非線程安全的構建單例的方法, 可是線程安全的主要就是這四種.
(1) : 餓漢式 : 加載類的時候就會進行實例化,,若是後續沒有用到,則會搞成資源浪費.
(2) : 懶漢式 : 使用的時候再去初始化,這樣在前幾回調用併發調用的時候,會出現資源競爭, 等待時間較久,可是後續再次調用的時候, 因爲是雙重判斷加加鎖校驗機制, 不會出現阻塞.
(3): 靜態內部類 : 也是在使用的時候再去加載內部類並初始化外部類的對象,第一次調用會比較慢.
(4):枚舉單例: 類加載的時候就穿建立好對象了, 特色和餓漢式很像.
上面是這幾種單例方式的特色,其中懶漢式,餓漢式,靜態內部類的方式都不能防止反射,只有枚舉類能夠防止反射.
可是通常咱們的應用程序只須要保證能夠正常實現單例便可,不必過多的去防止單例模式,咱們使用單例模式,就是想構造單例對象的,可是咱們本身又去使用反射去破壞單例模式,這不是本身給本身找麻煩嗎.