国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Java > 正文

JAVA實(shí)現(xiàn)單例模式的四種方法和一些特點(diǎn)

2019-11-26 16:13:13
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

一、餓漢式單例類

復(fù)制代碼 代碼如下:

public class Singleton 

    private Singleton(){ 

    } 

    private static Singleton instance = new Singleton(); 

    private static Singleton getInstance(){ 
        return instance; 
    } 

特點(diǎn):餓漢式提前實(shí)例化,沒(méi)有懶漢式中多線程問(wèn)題,但不管我們是不是調(diào)用getInstance()都會(huì)存在一個(gè)實(shí)例在內(nèi)存中

二、內(nèi)部類式單例類

復(fù)制代碼 代碼如下:

public class Singleton    
{       
        private Singleton(){    

    }    

    private class SingletonHoledr(){    
        private static Singleton instance = new Singleton();    
    }    

    private static Singleton getInstance(){    
        return SingletonHoledr.instance;    
    }    
}

特點(diǎn):內(nèi)部類式中,實(shí)現(xiàn)了延遲加載,只有我們調(diào)用了getInstance(),才會(huì)創(chuàng)建唯一的實(shí)例到內(nèi)存中.并且也解決了懶漢式中多線程的問(wèn)題.解決的方式是利用了Classloader的特性.

三、懶漢式單例類

復(fù)制代碼 代碼如下:

public class Singleton    
{       
    private Singleton(){    

    }    

    private static Singleton instance;    
    public static Singleton getInstance(){    
        if(instance == null){    
            return instance = new Singleton();    
        }else{    
            return instance;    
        }    
    }    
}  

特點(diǎn):在懶漢式中,有線程A和B,當(dāng)線程A運(yùn)行到第8行時(shí),跳到線程B,當(dāng)B也運(yùn)行到8行時(shí),兩個(gè)線程的instance都為空,這樣就會(huì)生成兩個(gè)實(shí)例。解決的辦法是同步:

可以同步但是效率不高:

復(fù)制代碼 代碼如下:

public class Singleton    
{       
    private Singleton(){    

    }    

    private static Singleton instance;    
    public static synchronized Singleton getInstance(){    
        if(instance == null){    
            return instance = new Singleton();    
        }else{    
            return instance;    
        }    
    }    
}

這樣寫程序不會(huì)出錯(cuò),因?yàn)檎麄€(gè)getInstance是一個(gè)整體的"critical section",但就是效率很不好,因?yàn)槲覀兊哪康钠鋵?shí)只是在第一個(gè)初始化instance的時(shí)候需要locking(加鎖),而后面取用instance的時(shí)候,根本不需要線程同步。

于是聰明的人們想出了下面的做法:

雙檢鎖寫法:

復(fù)制代碼 代碼如下:

public class Singleton{ 
  private static Singleton single;    //聲明靜態(tài)的單例對(duì)象的變量 
  private Singleton(){}    //私有構(gòu)造方法  

  public static Singleton getSingle(){    //外部通過(guò)此方法可以獲取對(duì)象   
    if(single == null){    
        synchronized (Singleton.class) {   //保證了同一時(shí)間只能只能有一個(gè)對(duì)象訪問(wèn)此同步塊       
            if(single == null){     
                single = new Singleton();         
        }    
      } 
    }   
    return single;   //返回創(chuàng)建好的對(duì)象  
  } 

思路很簡(jiǎn)單,就是我們只需要同步(synchronize)初始化instance的那部分代碼從而使代碼既正確又很有效率。
這就是所謂的“雙檢鎖”機(jī)制(顧名思義)。
很可惜,這樣的寫法在很多平臺(tái)和優(yōu)化編譯器上是錯(cuò)誤的。

原因在于:instance = new Singleton()這行代碼在不同編譯器上的行為是無(wú)法預(yù)知的。一個(gè)優(yōu)化編譯器可以合法地如下實(shí)現(xiàn)instance = new Singleton():

1. instance  = 給新的實(shí)體分配內(nèi)存

2. 調(diào)用Singleton的構(gòu)造函數(shù)來(lái)初始化instance的成員變量

現(xiàn)在想象一下有線程A和B在調(diào)用getInstance,線程A先進(jìn)入,在執(zhí)行到步驟1的時(shí)候被踢出了cpu。然后線程B進(jìn)入,B看到的是instance  已經(jīng)不是null了(內(nèi)存已經(jīng)分配),于是它開始放心地使用instance,但這個(gè)是錯(cuò)誤的,因?yàn)樵谶@一時(shí)刻,instance的成員變量還都是缺省值,A還沒(méi)有來(lái)得及執(zhí)行步驟2來(lái)完成instance的初始化。

當(dāng)然編譯器也可以這樣實(shí)現(xiàn):

1. temp = 分配內(nèi)存

2. 調(diào)用temp的構(gòu)造函數(shù)

3. instance = temp

如果編譯器的行為是這樣的話我們似乎就沒(méi)有問(wèn)題了,但事實(shí)卻不是那么簡(jiǎn)單,因?yàn)槲覀儫o(wú)法知道某個(gè)編譯器具體是怎么做的,因?yàn)樵贘ava的memory model里對(duì)這個(gè)問(wèn)題沒(méi)有定義。

雙檢鎖對(duì)于基礎(chǔ)類型(比如int)適用。很顯然吧,因?yàn)榛A(chǔ)類型沒(méi)有調(diào)用構(gòu)造函數(shù)這一步。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 安溪县| 彩票| 六安市| 桦川县| 通海县| 望奎县| 耿马| 铜川市| 嘉荫县| 长丰县| 临武县| 江源县| 揭阳市| 会东县| 勃利县| 保德县| 日喀则市| 静乐县| 寿光市| 岳西县| 安达市| 马关县| 龙里县| 高青县| 乌拉特后旗| 延吉市| 怀来县| 象州县| 虹口区| 宁武县| 怀远县| 杨浦区| 洮南市| 丽江市| 改则县| 穆棱市| 邻水| 永仁县| 巴林右旗| 颍上县| 泗水县|