Java學習筆記-單件模式

來源於headfirst設計模式html

單例模式的性能指標:lazy(是否延遲實例化),線程安全java

1、延遲實例化,同步(synchronized)方法-->因爲是單例更須要考慮處理問題須要考慮的同步問題,延遲實例化主要是面向資源敏感的對象設計模式

 1 public class Singleton {
 2 
 3     private static Singleton uniqueinstance;//惟一的實例變量
 4 
 5     private Singleton() {//私有的初始化方法
 6     }
 7 
 8     public static synchronized Singleton getInstance() {
 9     //實例的獲取方法,將普通的初始化方法變爲得到方法
10         if (uniqueinstance== null) {
11             uniqueinstance= new Singleton();//直接在類內部初始化
12         }
13         return instance;
14     }
15 }

 

2、直接實例化(靜態工廠方法)安全

 1 public class Singleton {
 2 
 3     private static Singleton uniqueInstance = new Singleton();
 4     //直接建立單例
 5     private Singleton() {
 6     }
 7 
 8     public static Singleton getInstance() {
 9 
10         return uniqueInstance;
11     }
12 }

 

3、雙重檢驗加鎖,雙重檢查鎖定模式首先驗證鎖定條件(第一次檢查),只有經過鎖定條件驗證才真正的進行加鎖邏輯並再次驗證條件(第二次檢查)。-->用來減小併發系統中競爭和同步的開銷。[http://zh.wikipedia.org/wiki/%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F]多線程

public class Singleton {

    private volatile static Singleton instance = null;//volatile變量

    private Singleton() {
    }

    public static Singleton getInstance() {

        if (instance == null) {//只有首次初始化時纔用到了同步模塊,避免了同步對資源的浪費
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

volatile變量的做用[參考:http://blog.csdn.net/orzorz/article/details/4319055]併發

用在多線程,爲了同步變量。在Java內存模型中,有main memory,每一個線程也有本身的memory (例如寄存器)。爲了性能,一個線程會在本身的memory中保持要訪問的變量的副本。這樣就會出現同一個變量在某個瞬間,在一個線程的memory中的值可能與另一個線程memory中的值,或者main memory中的值不一致的狀況。 
一個變量聲明爲volatile,就意味着這個變量是隨時會被其餘線程修改的,所以不能將它cache在線程memory中。synchronized的優點在於其能夠把方法或者代碼塊變爲原子操做,而volatile沒法。jvm

 4、枚舉單例,上面的方法都有一個問題就是反序列化,破壞了單例的特性,你能夠去查詢使用readResolve(),但比較麻煩,推薦使用Java的這個新特性——枚舉類型。它具備內置的序列化支持和線程安全支持。ide

public enum EasySingleton{性能

  INSTANCE;
}

在 java 垃圾回收中,描述了jvm運行時刻內存的分配。其中有一個內存區域是jvm虛擬機棧,每個線程運行時都有一個線程棧,線程棧保存了線程運行時候變量值信息。當線程訪問某一個對象時候值的時候,首先經過對象的引用找到對應在堆內存的變量的值,而後把堆內存變量的具體值load到線程本地內存中,創建一個變量副本,以後線程就再也不和對象在堆內存變量值有任何關係,而是直接修改副本變量的值,在修改完以後的某一個時刻(線程退出以前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就產生變化了。優化

[http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html]

5、各類優化

/**
 * 基於內部類的單例模式  Lazy  線程安全
 * 優勢:
 * 一、線程安全
 * 二、lazy
 * 缺點:
 * 一、待發現
 * 
 * @author laichendong
 * @since 2011-12-5
 */
public class SingletonFive {
    
    /**
     * 內部類,用於實現lzay機制
*/
    private static class SingletonHolder{
        /** 單例變量  */
        private static SingletonFive instance = new SingletonFive();
    }
    
    /**
     * 私有化的構造方法,保證外部的類不能經過構造器來實例化。
*/
    private SingletonFive() {
        
    }
    
    /**
     * 獲取單例對象實例
     * 
     * @return 單例對象
*/
    public static SingletonFive getInstance() {
        return SingletonHolder.instance;
    }
    
}

http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html

這種方式利用靜態內部類的優點,既是後實例化的又是線程安全的。

 

引伸閱讀:http://jiangzhengjun.iteye.com/blog/652440

http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

相關文章
相關標籤/搜索