方式一:首先不考慮併發的情況下:
public class Singleton{
private static Singleton singleton = null;
public Singleton getInstance(){
if(null == singleton){
singleton = new Singleton();
}
return singleton ;
}
}
方式二:加鎖(不考慮效率)
public class Solution {
private static Solution singleton = null;
public synchronized static Solution getInstance(){
if(null == singleton){
singleton = new Solution();
}
return singleton;
}
}
方式三:(雙重檢查加鎖DCL(Double-Check-Locked))
public class Solution {
/**
* @return: The same instance of this class every time
*/
private static Solution singleton = null;
public static Solution getInstance() {
if(singleton == null){
synchronized (Solution.class){
if(singleton == null){
try{
singleton = (Solution)Class.forName("Solution").newInstance();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
return singleton;
}
};
它的工作原理是:首先檢查是否在沒有同步的情況下需要初始化,如果singleton引用不爲空,則無需初始化,直接使用它即可。否則就進行同步並再次檢查singleton是否被初始化,從而保證了只有一個線程對singleton執行初始化。但是:在第一次檢查的時候,由於沒有采用同步,有可能得到一個“僅被部分構造的對象”,從而得到一個不正確(尚未初始化完成)的對象。產生這種糟糕結果的原因那就是java內存模型的指令衝排序現象——jvm爲了優化程序性能而對指令重新排序執行的現象。
優化方案則是
public class Singleton{
private volatile static Singleton singleton;
public static Singleton getInstance(){
if(null == singleton){
synchronized(Singleton.class){
if(null == singleton){
singleton = new Singleton();
}
}
}
return singleton;
}
}
不過該優化方案在java5.0及更高的版本中才能生效。DCL的這種方案已經被廣泛的廢棄掉了。更通用的做法是採用延遲化佔位類模式
方式四:即非延遲性加載方式,在類創建的同時就實例化一個singleton靜態對象,在第一次調用的時候,速度會比延遲化加載模式要快,因爲已經初始化完成。
public class Solution{
private static Solution singleton = new Solution();;
public static Solution getInstance(){
return singleton;
}
}
方式五:本質上同方式四沒有多大區別
public class Solution{
private static Solution singleton = null;
static {
singleton = new Solution();
}
public static Solution getInstance(){
return singleton;
}
}
方式六:靜態內部類(延遲化佔位類方式) JVM推遲Solution的初始化操作,當開始調用getInstance()的時候Solution纔會初始化,從而達到懶加載的目的。
public class TestClass{
public static Solution getInstance(){
return Solution.singleton;
}
static class Solution{
private static Solution singleton=new Solution();
}
}
方式七:枚舉類型實現單例模式
避免序列化和反序列化得到單例對象不相同,以及通過反射機制調用對象的私有構造方法來構造單例對象的弊端:
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}