單例設計模式基本上是用來控制創建許多對象,因此屬于家庭創建模式。
早期的趨勢是創建一個馬克斯的對象,但在某些情況下,我們需要一個固定數量的對象; 這種模式是正確的,來幫助我們。 通常,我們構造函數標記為私有,以確保外部世界不能創建對象,提供了一個靜態方法,簡單地返回對象。 它創建一個物體只有在沒有事先創建。
隨著時間的推移,人們意識到這種香草的實現單例,幾個問題,這是改善來解決這些問題。 注意,單件不對錯; 只要適合你的問題域。
在這次演講中,我們將看看不同實現的單例。
讓我們看看類圖:
單使用
有幾個地方是明智的使用單例模式。 例如:日志記錄、緩存、負載平衡、配置、通信(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服務器對象作為單件來適應您的需要。
學習快樂!