單例模式:深潛水

單例設計模式基本上是用來控制創建許多對象,因此屬于家庭創建模式。

早期的趨勢是創建一個馬克斯的對象,但在某些情況下,我們需要一個固定數量的對象; 這種模式是正確的,來幫助我們。 通常,我們構造函數標記為私有,以確保外部世界不能創建對象,提供了一個靜態方法,簡單地返回對象。 它創建一個物體只有在沒有事先創建。

隨著時間的推移,人們意識到這種香草的實現單例,幾個問題,這是改善來解決這些問題。 注意,單件不對錯; 只要適合你的問題域。

在這次演講中,我們將看看不同實現的單例。

讓我們看看類圖:

Paste_Image.png

單使用
有幾個地方是明智的使用單例模式。 例如:日志記錄、緩存、負載平衡、配置、通信(IO避免表現不佳或遠程)和數據庫連接池。 單例的Java API的一個例子是運行時類。

單例實現
這是香草的方式使用一個立即加載機制,實現一個單例是線程安全的。

public class MySingleton {
     private static final MySingleton mySingleton = new MySingleton();
     private MySingleton(){}     
     public static MySingleton getInstance(){
        return mySingleton;
     }
}

另一方面,這里有一個例子使用延遲加載機制實現單例。 在多線程應用程序中,這將是一個糟糕的方法。

class MySingleton {
     private static MySingleton mySingleton;
     private MySingleton(){}
     public static MySingleton getInstance(){
           if(null == mySingleton) {
                 mySingleton = new MySingleton();
           }
           return mySingleton;
     }
}

一個多線程的方法可以避免競態條件,以確保它不會違反一個單例的哲學。 但是在下面的例子中,使整個方法“同步”并不是一個好方法,因為我們需要把鎖對象創建語句。

class MySingleton {
     private static MySingleton mySingleton;
     private MySingleton(){}
     public synchronized static MySingleton getInstance(){      
        if(null == mySingleton) {
           mySingleton = new MySingleton();
        }
        return mySingleton;
     }
}

下面的多線程的實現方式可以避免競態條件,以確保它不會違反獨立的哲學和雙重檢查鎖定的幫助下使用對象級別的鎖會達到相同的。 這個實現保證線程安全; 但一直鎖所需的額外的對象是這不是一個很好的實踐。 另一個缺點是,有人可以使用類級別鎖你的鎖的優點是在一個不同的對象

class MySingleton {
  private static MySingleton mySingleton;
  private static final Object lock = new Object();
  private MySingleton(){}
  public static MySingleton getInstance(){
     if(null == mySingleton) {
         synchronized(lock) {
            if(null == mySingleton) {
               mySingleton = new MySingleton();
            }
         }   
     }
     return mySingleton;
  }
}

另一個multi-threaded-based實現(避免競態條件)的幫助下可以實現雙重檢查鎖定使用類級別鎖。 在這里,將MySingleton對象標記為不穩定將確保變化由一個線程應該在另一個是可見的。 這個實現保證線程安全。

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

這意味著實現提供了一個聰明的構造函數,將停止單合同違反使用反射。

class MySingleton {
    private volatile static MySingleton mySingleton;
    //Reflection can't hack to create more than one object.
    private MySingleton() throws Exception {
        if (null == mySingleton) {
            mySingleton = new MySingleton();
        } else {
            throw new Exception("It's a singleton class; don't expect more object to get produced");
        }
    }
    public static MySingleton getInstance() throws Exception {
        if (null == mySingleton) {
            synchronized(MySingleton.class) {
                if (null == mySingleton) {
                    mySingleton = new MySingleton();
                }
            }
        }
        return mySingleton;
    }
}

這是一個非常受歡迎的實現使用一個靜態類,這帶來了延遲加載和線程安全的權力。

public class MySingleton {
    private MySingleton() {}
    private static class SingletonUisngInner {
        private static MySingleton mySingleton = new MySingleton();
    }
    public static MySingleton getInstance() {
        return SingletonUisngInner.mySingleton;
    }
}

在某些情況下,如果你的單例類繼承接口可克隆屬性,那么你的單例類需要格外小心,防止單例設計合同。 你的單例類應該覆蓋的克隆方法和顯式地拋出CloneNotSupportedException。

class ClonedClass implements Cloneable {
    //Some logic
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class MySingleton extends ClonedClass {
    private MySingleton() {}
    private static class SingletonUisngInner {
        private static MySingleton mySingleton = new MySingleton();
    }
    public static OneMore getInstance() {
        return singletonUisngInner.mySingleton;
    }
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

另一個,我們的決賽,非常受歡迎的和智能的方法實現單例使用枚舉,而照顧我們到目前為止的所有問題。

public enum  EnumSingleton{
    INSTANCE;
}

有時,人們談論單件跨多個jvm,讓我們觸摸。 單身意味著只有一個對象,我們非常清楚,JVM對象生命周期管理,所以一個共享對象跨多個JVM是不可能的。

但是如果你需要,你可以在一個JVM中創建對象并分發它作為一個序列化的對象,可以使用其他JVM(但是記住,你反序列化,那么請記住,任何靜態或標記為瞬態將無法實現,某個地方,打破了單合同)。 你也可以嘗試使用RMI服務器對象作為單件來適應您的需要。

學習快樂!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,376評論 11 349
  • 單例模式(SingletonPattern)一般被認為是最簡單、最易理解的設計模式,也因為它的簡潔易懂,是項目中最...
    成熱了閱讀 4,298評論 4 34
  • 酒吧夜店讓我想起一首歌:一起搖擺。這首歌最能體現出在酒吧里的男男女女,搖擺著身體跟著音樂一起瘋狂的舞動。酒吧是尋歡...
    21029cbbb386閱讀 795評論 0 0
  • 昨夜秋雨倚風悄入,今偶感絲絲涼涼意 午間詩意興起執卷,拜讀納蘭性德雅作 容若能文能武能詩,妙筆敢愛敢恨敢歌 一代國...
    Alex0309閱讀 388評論 0 0