完美的單例模式建立

  今天把設計模式拿出來看了下,發現之前對於單例模式的理解非常膚淺,沒考慮線程安全,在考慮了線程安全的狀況下又沒考慮性能,固然我遇到的系統都不怎麼考慮併發性能,因此其實也無所謂,當看到單例模式的時候,上網搜索了下,發下一片很好的帖子,我把其中的單例模式整理了下,給了個結果出來。html

  帖子地址:http://blog.csdn.net/zhangerqing/article/details/8194653java

  前提都是在考慮線程安全的狀況下,能夠有兩種狀況。分別是懶漢式和餓漢式的一種實現。sql

  1.性能不太好,每次鎖對象,固然若是你遇到的跟我遇到的系統都同樣不考慮性能問題,其實這麼作也沒問題,可是很差。正如Oracle高級編程裏面所說的那樣,你的sql能正確的完成任務,但並不表明他能很好的完成任務。編程

  2.咱們只但願在第一次getInstance的時候去實例化對象,這個就作到了,而且線程安全,可是若是類加載的時候出問題仍是有可能出問題,因此借用那篇帖子裏說的,要完成完美的實現是不可能的,咱們只能根據實際狀況來選擇合適的方式。設計模式

  1.直接鎖整個對象,保證線程安全,可是因爲每次獲取都會鎖對象,性能很差,也不是咱們但願的。安全

package singlePattern;

/**
 * Thread safe single pattern, but performance is poor, because every time we will lock the instance,
 * we hope lock the instance on first time but all times
 * 
 * @author Administrator
 * 
 */
public class SinglePattern {

    // private instance
    private static SinglePattern instance = null;

    // private constructor
    private SinglePattern() {
    }

    // public getInstance method
    public synchronized static SinglePattern getInstance() {
        if (instance == null) {
            instance = new SinglePattern();
        }
        return instance;
    }
}

  2.咱們須要的情形是在第一次初始化須要同步,以後的調用就不須要考慮線程同步。因爲JVM在加載類的時候是互斥的,咱們知道類加載器在加載類的時候會直接把靜態變量和靜態代碼塊執行一次,而後再去去調用普通代碼快,而後去調用構造方法初始化堆,而後在返回引用賦值給棧裏面的引用。因而咱們能夠利用類加載的靜態變量和靜態代碼塊來安全的構造單例實例。併發

  

package singlePattern;

/**
 * Thread safe and performance good.
 * @author Administrator
 *
 */
public class UserSinglePattern {
    
    // private constructor
    private UserSinglePattern() {}
    
    // static inner class, for create a single pattern instance
    private static class NewInstance {
        private static UserSinglePattern instance = new UserSinglePattern();
    }
    
    // the get method for single pattern instance
    public static UserSinglePattern getInstance() {
        return NewInstance.instance;
    }
}

  3.若是實例採用靜態的就能實如今類加載的時候線程安全的初始化實例,可是卻不能實現lazy加載,而採用上面的靜態內部類的方式就能實現lazy加載,由於虛擬機機制是須要調用getInstance()方法的時候纔會加載靜態內部類,若是不調用那麼他是不會被加載的。下面是測試代碼,同時擁有2個靜態內部類來建立對象,可是隻調用其中一個那麼就只會加載一個,另一個是不會被加載的。ide

public class SinglePatternThreadSafe {
    
    // 私有構造方法
    private SinglePatternThreadSafe() {
        System.out.println(123);
    }
    
    private SinglePatternThreadSafe(String str) {
        System.out.println(321);
    }
    
    // 內部類,利用類加載的互斥性來達到單例的建立
    private static class NewInstance {
        private static SinglePatternThreadSafe instance = new SinglePatternThreadSafe();
    }
    
    private static class NewInstance1 {
        private static SinglePatternThreadSafe in = new SinglePatternThreadSafe("11");
    }
    
    // 返回實例的公共方法
    public static SinglePatternThreadSafe getInstance() {
        return NewInstance.instance;
    }
    
    public static SinglePatternThreadSafe getInstance(String str) {
        return NewInstance1.in;
    }
    
    public static void main(String[] args) {
        SinglePatternThreadSafe.getInstance();
    }
  // 只打印出123而沒有打印11 }

再貼下我參考的地址對做者表示感謝:http://blog.csdn.net/zhangerqing/article/details/8194653性能

這個也寫的很好:http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html測試

這篇也測試了若是在不調用靜態內部類的方法或者變量或者常量的時候內部類是不會被加載的,http://yongliang567.iteye.com/blog/904467

相關文章
相關標籤/搜索