Java單例模式以及線程安全性的保證



1.單例模式有什麼用處?java

有一些對象只能使用一個,例如:數據庫鏈接、線程池(threadpool)、緩存(cache)、對話框、處理偏好(preferences)設置和這側表(registry)的對象、日誌對象、充當打印機、顯卡等設備的驅動程序的對象,即用於管理共享的資源。這種對象只能有一個實例,製造多個會致使問題。數據庫


2.最經典的單例模式?緩存

        /**
     * 1.利用一個私有靜態變量來記錄Singleton類的惟一實例;
     * 2.構造器聲明爲私有,只有Singleton類自己內部纔可調用;
     * 3.聲明共有靜態的方法getInstance()來實例化對象,並返回這個對象的實例;
     * 4.說明:若是咱們不須要這個實例,就不會調用getInstance()方法,那麼這個實例就不會產生,
     *        稱爲「延遲實例化(lazy instantiaze)」。這種作法對資源敏感的對象特別重要。
     */
    public class Singleton {
    
        private static Singleton sInstance;
        
        private Singleton(){}
        
        public static Singleton getInstance(){
            if(sInstance == null){
                sInstance = new Singleton();
            }
            return sInstance;
        }
    }

3.單例模式定義--確保一個類只有一個實例,並提供一個全局訪問點
安全

(1)全局訪問點即向外提供的獲取惟一實例的惟一入口,是共有靜態的,訪問它對比訪問通常的全局變量的優勢在於:單例中的全局訪問點能夠作到「延遲實例化」。多線程

(2)此時的單例可能遇到的麻煩--多線程ide

         正以下圖中狀況所示,當有多個線程同時訪問該訪問點時,以兩個線程爲例,就會出現可能實例化兩個對象,這對於使用單例的地方可能引起災難呀...
spa

wKioL1aXabSTXBuEAACodDIn338308.jpg


4.怎樣改善多線程狀況下的單例?線程

(1)不推薦的方法--synchronized日誌

        同步getInstance()方法既簡單又有效,可是可能形成程序執行效率降低100倍,若是getInstance()被調用的頻繁,只能從新考慮其餘方法了;對象

(2)什麼都不作

        沒錯,什麼都不作。若是應用程序能夠接受getInstance()形成的額外負擔,那就徹底能夠忘記這件事;

(3)使用「急切實例化(eagerly)」而非「延遲實例化」的作法

        a.若是應用程序老是須要建立使用單例實例;

        b.若是應用程序在建立運行時方面的負擔不過重;

        此時可選擇「急切實例化」:

        public class EagerlySingleton {        
            /**在靜態初始化器中建立單例實例,保證了線程安全**/
            private static EagerlySingleton eSingletonInstance = new EagerlySingleton();
            
            private EagerlySingleton(){};
            
            public static EagerlySingleton getInstance(){
                return eSingletonInstance;
            }
        }

        這個作法,依賴JVM在加載這個類時就建立這個惟一的單例實例,保證了任何線程在訪問這個靜態變量以前,該實例已經建立。

(4)用「雙重檢查加鎖(double checked locking)」,在getInstance()中減小使用同步

    /**    
     * 1.volatile確保實例化時,多個線程能正確的處理sInstance;
     * 2.判斷sInstance == null後在使用synchronized,且synchronized後在判斷一次sInstance == null
     * 3.雙重檢查加鎖不適用於1.4以及更早的版本的Java。
     */
    public class DoubleCheckSingleton {
    
        private volatile static DoubleCheckSingleton sInstance;
        
        private DoubleCheckSingleton(){}
        
        public static DoubleCheckSingleton getInstance(){
            if(sInstance == null){
                synchronized (DoubleCheckSingleton.class) {
                    if(sInstance == null){
                        sInstance = new DoubleCheckSingleton();
                    }
                }
            }
            return sInstance;
        }
    }
相關文章
相關標籤/搜索