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

首頁 > 編程 > Java > 正文

Java中單例模式的幾種實(shí)現(xiàn)方式

2019-11-06 06:11:50
字體:
供稿:網(wǎng)友

學(xué)習(xí)java的同學(xué)注意了!!! 學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群,群號碼:523047986  我們一起學(xué)Java!

1 線程不安全的實(shí)現(xiàn)方法

首先介紹java中最基本的單例模式實(shí)現(xiàn)方式,我們可以在一些初級的java書中看到。這種實(shí)現(xiàn)方法不是線程安全的,所以在項(xiàng)目實(shí)踐中如果涉及到線程安全就不會使用這種方式。但是如果不需要保證線程安全,則這種方式還是不錯的,因?yàn)樗枰拈_銷比較小。下面是具體的實(shí)現(xiàn)代碼:

 

復(fù)制代碼
public Class Singleton{  PRivate static Singleton instance = null;  private Singleton(){}  public  static Singleton getInstance()  {     if( instance == null)        instance = new Singleton ();     return instance;  }}    復(fù)制代碼

 

我們說過這種實(shí)現(xiàn)方式不是thread-safe的,那么可以把上面的方法變成線程安全的嗎?當(dāng)然可以,在方法getInstance()上加上synchronized修飾符就可以實(shí)現(xiàn)方法的同步了。但是這樣系統(tǒng)開銷會很大。具體代碼如下:

 

復(fù)制代碼
public Class Singleton{  private static Singleton instance = null;  private Singleton(){}  public  static synchronized  Singleton getInstance()  {     if( instance == null)        instance = new Singleton ();     return instance;  }}    復(fù)制代碼

每次有線程調(diào)用getInstance()方法,都需要同步判斷。這顯然不是最好的選擇,下面將會陸續(xù)介紹幾種thread-safe的方法。

 

2 兩種lazy loaded thread-safe的單例模式實(shí)現(xiàn)方式

1) DCL (double checked locking 實(shí)現(xiàn)法)

    double checked locking ,顧名思義,就是雙檢查法,檢查實(shí)例INSTANCE是否為null或者已經(jīng)實(shí)例化了。下面是具體的實(shí)現(xiàn)代碼:

復(fù)制代碼
 1 public class DoubleCheckedLockingSingleton{ 2      private volatile DoubleCheckedLockingSingleton INSTANCE; 3   4      private DoubleCheckedLockingSingleton(){} 5   6      public DoubleCheckedLockingSingleton getInstance(){ 7          if(INSTANCE == null){ 8             synchronized(DoubleCheckedLockingSingleton.class){ 9                 //double checking Singleton instance10                 if(INSTANCE == null){11                     INSTANCE = new DoubleCheckedLockingSingleton();12                 }13             }14          }15          return INSTANCE;16      }17 }復(fù)制代碼

這種方法也很好理解,我們可以看到有兩次對instance是否為null的判斷:如果第一次判斷不為空,則直接返回實(shí)例就可以了;如果instance為空,則進(jìn)入同步代碼塊再進(jìn)行null值判斷,再選擇是否實(shí)例化。第一個null判斷可以減少系統(tǒng)的開銷。在實(shí)際項(xiàng)目中做過多線程開發(fā)的都應(yīng)該知道DCL。

 

2) lazy initialization holder class 模式實(shí)現(xiàn)法

下面是這種方法的實(shí)現(xiàn)代碼:

復(fù)制代碼
public class Singleton {    /**     * 類級的內(nèi)部類,也就是靜態(tài)的成員式內(nèi)部類,該內(nèi)部類的實(shí)例與外部類的實(shí)例     * 沒有綁定關(guān)系,而且只有被調(diào)用到才會裝載,從而實(shí)現(xiàn)了延遲加載     */    private static class SingletonHolder{        /**         * 靜態(tài)初始化器,由JVM來保證線程安全         */        private static Singleton instance = new Singleton();    }    /**     * 私有化構(gòu)造方法     */    private Singleton(){    }    public static  Singleton getInstance(){        return SingletonHolder.instance;    }}復(fù)制代碼

 

當(dāng)getInstance方法第一次被調(diào)用的時候,它第一次讀取SingletonHolder.instance,導(dǎo)致SingletonHolder類得到初始化;而這個類在裝載并被初始化的時候,會初始化它的靜態(tài)域,從而創(chuàng)建Singleton的實(shí)例,由于是靜態(tài)的域,因此只會被虛擬機(jī)在裝載類的時候初始化一次,并由虛擬機(jī)來保證它的線程安全性。這個模式的優(yōu)勢在于,getInstance方法并沒有被同步,并且只是執(zhí)行一個域的訪問,因此延遲初始化并沒有增加任何訪問成本。

 

關(guān)于延遲初始化(lazy loaded)

“除非絕對必要,否則就不要延遲初始化”。延遲初始化是一把雙刃劍,它降低了初始化類或者創(chuàng)建實(shí)例的開銷,卻增加了訪問被延遲初始化的域的開銷,考慮到延遲初始化的域最終需要初始化的開銷以及域的訪問開銷,延遲初始化實(shí)際上降低了性能。

 

3 靜態(tài)工廠實(shí)現(xiàn)法

  因?yàn)閱卫庆o態(tài)的final變量,當(dāng)類第一次加載到內(nèi)存中的時候就初始化了,其thread-safe性由JVM來負(fù)責(zé)保證。值得注意的是這個實(shí)現(xiàn)方式不是lazy-loadedd的。   具體實(shí)現(xiàn)代碼如下:

復(fù)制代碼
 1 public class Singleton{ 2     //initailzed during class loading 3     private static final Singleton INSTANCE = new Singleton(); 4   5     private Singleton(){} 6   7     public static Singleton getSingleton(){ 8         return INSTANCE; 9     }10 }復(fù)制代碼

 

4 枚舉實(shí)現(xiàn)單例(Enum Singleton)

  枚舉單例(Enum Singleton)是實(shí)現(xiàn)單例模式的一種新方式,枚舉這個特性是在Java5才出現(xiàn)的,在《Effective Java》一書中有介紹這個特性。下面是這種方法的具體實(shí)現(xiàn)代碼:

復(fù)制代碼
public enum Singleton {      INSTANCE("hello") {          public void someMethod() {              // . . .          }      };      private String name;    private void PrintName(){System.out.println(name);}    protected abstract void someMethod();  } 復(fù)制代碼

你可以通過Singleton.INSTANCE來訪問該單示例變量。默認(rèn)枚舉實(shí)例的創(chuàng)建是線程安全的,但是在枚舉中的其他任何方法由程序員自己負(fù)責(zé)。如果你正在使用實(shí)例方法,那么你需要確保線程安全(如果它影響到其他對象的狀態(tài)的話)。傳統(tǒng)單例存在的另外一個問題是一旦你實(shí)現(xiàn)了序列化接口,那么它們不再保持單例了,但是枚舉單例,JVM對序列化有保證。枚舉實(shí)現(xiàn)單例的好處:有序列化和線程安全的保證,代碼簡單。

學(xué)習(xí)Java的同學(xué)注意了!!! 學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群,群號碼:523047986  我們一起學(xué)Java!


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 吕梁市| 安康市| 广丰县| 留坝县| 梅河口市| 江孜县| 石楼县| 东丽区| 建昌县| 永善县| 霍邱县| 明溪县| 庄河市| 余干县| 黄冈市| 红桥区| 于田县| 敦煌市| 肃南| 宁化县| 正宁县| 会昌县| 依安县| 理塘县| 民权县| 翼城县| 个旧市| 葵青区| 罗源县| 三穗县| 桓仁| 新河县| 林西县| 准格尔旗| 修水县| 盐山县| 尉犁县| 阿尔山市| 芒康县| 金秀| 安福县|