【轉(zhuǎn)】線程安全的單例模式

轉(zhuǎn)自:http://blog.csdn.net/willamlan/article/details/48596237

設(shè)計(jì)模式之-------單例模式


在現(xiàn)有的23種設(shè)計(jì)模式中,可以說單例模式是所有設(shè)計(jì)模式中最簡(jiǎn)單的一種。

單例模式就是說系統(tǒng)中對(duì)于某類的只能有一個(gè)對(duì)象,不可能再出來第二個(gè)。

通過單例模式,自行實(shí)例化并向這個(gè)系統(tǒng)提供這個(gè)單一實(shí)例的訪問方法。

單例模式也是23中設(shè)計(jì)模式中在面試時(shí)少數(shù)幾個(gè)會(huì)要求寫代碼的模式之一。

主要考察的是多線程下單例模式的線程安全性問題。

單例模式實(shí)例一(不使用同步鎖)

    public class Singleton {  
        private static Singleton sin=new Singleton();    ///直接初始化一個(gè)實(shí)例對(duì)象  
        private Singleton(){    ///private類型的構(gòu)造函數(shù),保證其他類對(duì)象不能直接new一個(gè)該對(duì)象的實(shí)例  
        }  
        public static Singleton getSin(){    ///該類唯一的一個(gè)public方法      
            return sin;  
        }  
    }  

上述代碼中的一個(gè)缺點(diǎn)是該類加載的時(shí)候就會(huì)直接new 一個(gè)靜態(tài)對(duì)象出來,當(dāng)系統(tǒng)中這樣的類較多時(shí),會(huì)使得啟動(dòng)速度變慢 ?,F(xiàn)在流行的設(shè)計(jì)都是講“延遲加載”,我們可以在第一次使用的時(shí)候才初始化第一個(gè)該類對(duì)象。所以上述這種只適合在小系統(tǒng)。

單例模式實(shí)例二(使用同步方法)

public class Singleton {    
     private static Singleton instance;    
     private Singleton (){  
           
     }     
     public static synchronized Singleton getInstance(){    //對(duì)獲取實(shí)例的方法進(jìn)行同步  
       if (instance == null)       
         instance = new Singleton();   
       return instance;  
     }  
 } 

  上述代碼中的一次鎖住了一個(gè)方法, 這個(gè)粒度有點(diǎn)大 ,改進(jìn)就是只鎖住其中的new語句就OK。就是所謂的“雙重鎖”機(jī)制。
單例模式實(shí)例三(使用雙重同步鎖)

    public class Singleton {    
         private static Singleton instance;    
         private Singleton (){  
         }     
         public static Singleton getInstance(){    //對(duì)獲取實(shí)例的方法進(jìn)行同步  
           if (instance == null){  
               synchronized(Singleton.class){  
                   if (instance == null)  
                       instance = new Singleton();   
               }  
           }  
           return instance;  
         }  
     }  

附注:根據(jù)此單一實(shí)例產(chǎn)生的時(shí)機(jī)不同(當(dāng)然,都是指第一次,也是唯一一次產(chǎn)生此單一實(shí)例時(shí)),可以將其分為懶漢式、餓漢式和登記式。
一、懶漢式:
其特點(diǎn)是延遲加載,即當(dāng)需要用到此單一實(shí)例的時(shí)候,才去初始化此單一實(shí)例。如上面的單例模式實(shí)例二。

二、餓漢式:
餓漢式的特點(diǎn)是應(yīng)用中尚未需要用到此單一實(shí)例的時(shí)候即先實(shí)例化。如上面的單例模式實(shí)例一。

三、登記式單例模式:
登記式單例模式,一般是通過一個(gè)專門的類對(duì)各單例模式的此單一實(shí)例進(jìn)行管理和維護(hù)。通過Map方式可以方便的實(shí)現(xiàn)此中目的。常見的代碼如下:

    import java.util.HashMap;  
    import java.util.Map;  
      
    public class SingleTonManager {  
      
        private static Map singleTonMap = new HashMap();  
      
        public static void main(String[] args) {  
            // 獲取A類的單例  
            A a = (A) getInstance(A.class.getName());  
            // 獲取B類的單例  
            B b = (B) getInstance(B.class.getName());  
        }  
      
        // 根據(jù)類型獲取單例  
        public static Object getInstance(String className) {  
            // 判斷singleTonMap中是否有此單例,有則取得后返回,無則添加單例后返回  
            if (!singleTonMap.containsKey(className)) {  
                try {  
                    singleTonMap.put(className, Class.forName(className).newInstance());  
                } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            }  
            return singleTonMap.get(className);  
        }  
    }  
      
    class A {  
      
    }  
    class B {  
      
    }  

四、改進(jìn)型懶漢式(直接滿足線程安全)——通過靜態(tài)內(nèi)部類實(shí)現(xiàn)
在如上的懶漢單例模式中,對(duì)于多線程環(huán)境中。可以通過常見的如synchronized等方式實(shí)現(xiàn)線程安全,同時(shí),可以通過Java靜態(tài)內(nèi)部類的方式實(shí)現(xiàn)進(jìn)一步改進(jìn)。
常見代碼如下:

    public class SingleTon {  
      
        // 利用靜態(tài)內(nèi)部類特性實(shí)現(xiàn)外部類的單例  
        private static class SingleTonBuilder {  
            private static SingleTon singleTon = new SingleTon();  
        }  
      
        // 私有化構(gòu)造函數(shù)  
        private SingleTon() {  
      
        }  
      
        public static SingleTon getInstance() {  
            return SingleTonBuilder.singleTon;  
        }  
      
        public static void main(String[] args) {  
            SingleTon instance = getInstance();  
        }  
    }  

其主要原理為:Java中靜態(tài)內(nèi)部類可以訪問其外部類的成員屬性和方法,同時(shí),靜態(tài)內(nèi)部類只有當(dāng)被調(diào)用的時(shí)候才開始首次被加載,利用此特性,可以實(shí)現(xiàn)懶漢式,在靜態(tài)內(nèi)部類中靜態(tài)初始化外部類的單一實(shí)例即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容