設計模式(五)——單例模式
阿新 • • 發佈:2018-12-12
單例模式,主要由以下幾個模組組成:私有的靜態物件例項,私有的構造方法(避免外部呼叫new物件,保證只有一個物件的例項),一個共有的靜態獲取物件的方法(供外部呼叫)。
程式碼如下:
懶漢式單例模式(在需要的時候,也即呼叫共有的靜態獲取物件的方法時才建立物件):
package SinglePattern; public class LazySingle { private static LazySingle newInstance = null; private LazySingle(){ } public static LazySingle getInstance(){ if(newInstance == null){ System.out.println("呼叫時建立物件。"); newInstance = new LazySingle(); } return newInstance; } }
懶漢式單例模式是執行緒不安全的(比如兩個執行緒同時執行getInstance方法,執行緒A執行到 newInstance = new LazySingle()的時候等待記憶體分配,此時執行緒B也執行到 if(newInstance == null),判斷返回是true,那麼程式中就可能出現兩個物件),可以做如下改進:
優化一(用synchronized):
package SinglePattern; public class LazySingle { private static LazySingle newInstance = null; private LazySingle(){ } public static synchronized LazySingle getInstance(){ if(newInstance == null){ System.out.println("呼叫時建立物件。"); newInstance = new LazySingle(); } return newInstance; } }
優化二(用synchronized,更加細粒度,即雙重檢驗):
package SinglePattern; public class LazySingle { private static LazySingle newInstance = null; private LazySingle(){ } public static LazySingle getInstance(){ if(newInstance == null){ synchronized (LazySingle.class) { if(newInstance == null){ newInstance = new LazySingle(); } } } return newInstance; } }
優化三(用靜態內部類,classloader機制在類載入的時候並不會載入靜態內部類,也就不會建立物件的例項,只有當呼叫獲取物件的方法時才會載入內部類,建立物件的例項):
package SinglePattern;
public class LazySingle {
private static LazySingle newInstance = null;
private LazySingle(){
}
private static class SingleHolder{
private static final LazySingle newInstance = new LazySingle();
}
public static final LazySingle getInstance(){
return SingleHolder.newInstance;
}
}
餓漢式單例模式(不管需不需要物件例項,在類載入的時候就建立好類的例項,利用classloader機制避免了執行緒安全的問題):
package SinglePattern;
public class HungrySingle {
private static HungrySingle newInstance = new HungrySingle();
private HungrySingle(){
}
public static HungrySingle getInstance(){
System.out.println("呼叫時已經建立好了物件。");
return newInstance;
}
}
總結:一般情況下使用餓漢式單例模式,在特定的懶載入模式下(初始化很耗費資源,但是並不常用)可以使用靜態內部類的方式,其他情況下使用synchronized雙重檢驗的模式。
參考文件:設計模式|菜鳥教程,《設計模式之禪》