1. 程式人生 > >設計模式(五)——單例模式

設計模式(五)——單例模式

單例模式,主要由以下幾個模組組成:私有的靜態物件例項,私有的構造方法(避免外部呼叫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雙重檢驗的模式。

參考文件:設計模式|菜鳥教程,《設計模式之禪》