<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      所謂單例就是在系統(tǒng)中只有一個(gè)該類(lèi)的實(shí)例。
      單例模式的核心分以下三個(gè)步驟:

      * 構(gòu)造方法私有化。即不能在類(lèi)外實(shí)例化,只能在類(lèi)內(nèi)實(shí)例化。
      * 在本類(lèi)中創(chuàng)建本類(lèi)的實(shí)例。
      * 在本類(lèi)中提供給外部獲取實(shí)例的方式。
      單例模式的實(shí)現(xiàn)方式有兩種:餓漢模式和懶漢模式。

      餓漢模式

      不管現(xiàn)在需不需要,先創(chuàng)建實(shí)例。關(guān)鍵在于“餓”,餓了就要立即吃。

      靜態(tài)常量


      這里將類(lèi)的構(gòu)造器私有化,就不能在外部通過(guò)new關(guān)鍵字創(chuàng)建該類(lèi)的實(shí)例,然后定義了一個(gè)該類(lèi)的常量,用static修飾,以便外部能夠獲得該類(lèi)實(shí)例(通過(guò)HungryStaticConstantSingleton.
      INSTANCE獲得)。也可以不加final關(guān)鍵字,具體看自己的需求。
      1 /** 2 * 惡漢模式-靜態(tài)常量,簡(jiǎn)潔直觀 3 */ 4 public class
      HungryStaticConstantSingleton{ 5 //構(gòu)造器私有化 6 private
      HungryStaticConstantSingleton() { 7 } 8 //靜態(tài)變量保存實(shí)例變量 并提供給外部實(shí)例 9 public final
      static HungryStaticConstantSingleton INSTANCE = new
      HungryStaticConstantSingleton();10 }
      ?

      枚舉

      這種方式是最簡(jiǎn)潔的,不需要考慮構(gòu)造方法私有化。值得注意的是枚舉類(lèi)不允許被繼承,因?yàn)槊杜e類(lèi)編譯后默認(rèn)為final
      class,可防止被子類(lèi)修改。常量類(lèi)可被繼承修改、增加字段等,容易導(dǎo)致父類(lèi)的不兼容。
      /** * 惡漢-枚舉形式,最簡(jiǎn)潔 */ public enum HungryEnumSingleton{ INSTANCE; public void
      print(){ System.out.println("這是通過(guò)枚舉獲得的實(shí)例"); System.out.println(
      "HungryEnumSingleton.pring()"); } }
      ?

      Test,打印實(shí)例直接輸出了【INSTANCE】,是因?yàn)槊杜e幫我們實(shí)現(xiàn)了toString,默認(rèn)打印名稱(chēng)。
      public class EnumSingleton2Test{ public static void main(String[] args) {
      HungryEnumSingleton singleton2= HungryEnumSingleton.INSTANCE;
      System.out.println(singleton2); singleton2.print(); } }
      ?輸出結(jié)果



      ?

      靜態(tài)代碼塊


      這種方式和上面的靜態(tài)常量/變量類(lèi)似,只不過(guò)把new放到了靜態(tài)代碼塊里,從簡(jiǎn)潔程度上比不過(guò)第一種。但是把new放在static代碼塊有別的好處,那就是可以做一些別的操作,如初始化一些變量,從配置文件讀一些數(shù)據(jù)等。
      /** * 惡漢模式-靜態(tài)代碼塊 */ public class HungryStaticBlockSingleton{ //構(gòu)造器私有化 private
      HungryStaticBlockSingleton() { }//靜態(tài)變量保存實(shí)例變量 public static final
      HungryStaticBlockSingleton INSTANCE;static { INSTANCE = new
      HungryStaticBlockSingleton(); } }
      ?

      如下,在static代碼塊里讀取?info.properties 配置文件動(dòng)態(tài)配置的屬性,賦值給 info 字段。
      /** * 惡漢模式-靜態(tài)代碼塊 * 這種用于可以在靜態(tài)代碼塊進(jìn)行一些初始化 */ public class
      HungryStaticBlockSingleton{private String info; private
      HungryStaticBlockSingleton(String info) {this.info = info; } //構(gòu)造器私有化 private
      HungryStaticBlockSingleton() { }//靜態(tài)變量保存實(shí)例變量 public static final
      HungryStaticBlockSingleton INSTANCE;static { Properties properties = new
      Properties();try { properties.load(HungryStaticBlockSingleton.class
      .getClassLoader().getResourceAsStream("info.properties")); } catch (IOException
      e) { e.printStackTrace(); } INSTANCE= new
      HungryStaticBlockSingleton(properties.getProperty("info")); } public String
      getInfo() {return info; } public void setInfo(String info) { this.info = info;
      } }
      ?

      Test,
      public class HungrySingletonTest{ public static void main(String[] args) {
      HungryStaticBlockSingleton hun= HungryStaticBlockSingleton.INSTANCE;
      System.out.println(hun.getInfo()); } }
      ?

      輸出



      ?

      懶漢模式

      需要時(shí)再創(chuàng)建,關(guān)鍵在于“懶”,類(lèi)似懶加載。

      非線程安全


      同樣是構(gòu)造方法私有化,提供給外部獲得實(shí)例的方法,getInstance()方法被調(diào)用時(shí)創(chuàng)建實(shí)例。該方式適用于單線程,因?yàn)樵诙嗑€程的情況下可能會(huì)發(fā)生線程安全問(wèn)題,導(dǎo)致創(chuàng)建不同實(shí)例的情況發(fā)生??梢钥聪旅娴难菔?。
      1 /** 2 * 懶漢模式-線程不安全的,適用于單線程 3 */ 4 public class LazyUnsafeSingleton{ 5
      private LazyUnsafeSingleton(){ 6 } 7 private static LazyUnsafeSingleton
      instance; 8 public static LazyUnsafeSingleton getInstance(){ 9 if(instance==
      null){ 10 instance = new LazyUnsafeSingleton(); 11 } 12 return instance; 13 }
      14 }
      非線程安全演示
      1 public class LazyUnsafeSingletionTest{ 2 public static void main(String[]
      args)throws ExecutionException, InterruptedException { 3 ExecutorService es =
      Executors.newFixedThreadPool(2); 4 Callable<LazyUnsafeSingleton> c1 = new
      Callable<LazyUnsafeSingleton>(){ 5 @Override 6 public LazyUnsafeSingleton
      call()throws Exception { 7 return LazyUnsafeSingleton.getInstance(); 8 } 9
      };10 Callable<LazyUnsafeSingleton> c2 = new Callable<LazyUnsafeSingleton>(){ 11
      @Override12 public LazyUnsafeSingleton call() throws Exception { 13 return
      LazyUnsafeSingleton.getInstance();14 } 15 }; 16 Future<LazyUnsafeSingleton>
      submit = es.submit(c1); 17 Future<LazyUnsafeSingleton> submit1 = es.submit(c2);
      18 LazyUnsafeSingleton lazyUnsafeSingleton = submit.get(); 19
      LazyUnsafeSingleton lazyUnsafeSingleton1 = submit1.get(); 20 es.shutdown(); 21
      22 System.out.println(lazyUnsafeSingleton); 23
      System.out.println(lazyUnsafeSingleton);24
      System.out.println(lazyUnsafeSingleton1==lazyUnsafeSingleton); 25 } 26 }
      ?

      輸出?大概運(yùn)行三次就會(huì)出現(xiàn)一次,我們可以在?LazyUnsafeSingleton 中判斷?if(instance==null)
      之后增加線程休眠以獲得更好的效果。



      線程安全的


      該方式是懶漢模式中線程安全的創(chuàng)建方式。通過(guò)同步代碼塊控制并發(fā)創(chuàng)建實(shí)例。并且采用雙重檢驗(yàn),當(dāng)兩個(gè)線程同時(shí)執(zhí)行第一個(gè)判空時(shí),都滿(mǎn)足的情況下,都會(huì)進(jìn)來(lái),然后去爭(zhēng)鎖,假設(shè)線程1拿到了鎖,執(zhí)行同步代碼塊的內(nèi)容,創(chuàng)建了實(shí)例并返回,此時(shí)線程2又獲得鎖,執(zhí)行同步代碼塊內(nèi)的代碼,因?yàn)榇藭r(shí)線程1已經(jīng)創(chuàng)建了,所以線程2雖然拿到鎖了,如果內(nèi)部不加判空的話,線程2會(huì)再new一次,導(dǎo)致兩個(gè)線程獲得的不是同一個(gè)實(shí)例。線程安全的控制其實(shí)是內(nèi)部判空在起作用,至于為什么要加外面的判空下面會(huì)說(shuō)。
      /** * 懶漢模式-線程安全,適用于多線程 */ public class LazySafeSingleton{ private static
      volatile LazySafeSingleton safeSingleton;//防止指令重排 private LazySafeSingleton() {
      }public static LazySafeSingleton getInstance(){ if(safeSingleton==null){
      synchronized (LazySafeSingleton.class){ if(safeSingleton==null){//雙重檢測(cè)
      safeSingleton =new LazySafeSingleton(); } } } return safeSingleton; } }
      ?當(dāng)不加內(nèi)層判空時(shí),會(huì)出現(xiàn)不是單例的情況,只不過(guò)出現(xiàn)的概率更低了點(diǎn)。



      可不可以只加內(nèi)層判空呢?答案是可以。

      那為什么還要加外層判空的呢?
      內(nèi)層判空已經(jīng)可以滿(mǎn)足線程安全了,加外層判空的目的是為了提高效率。因?yàn)榭赡艽嬖谶@樣的情況:線程1拿到鎖后執(zhí)行同步代碼塊,在new之后,還沒(méi)有釋放鎖的時(shí)候,線程2過(guò)來(lái)了,它在等待鎖(此時(shí)線程1已經(jīng)創(chuàng)建了實(shí)例,只不過(guò)還沒(méi)釋放鎖,線程2就來(lái)了),然后線程1釋放鎖后,線程2拿到鎖,進(jìn)入同步代碼塊匯總,判空,返回。這種情況線程2是不是不用去等待鎖了?所以在外層又加了一個(gè)判空就是為了防止這種情況,線程2過(guò)來(lái)后先判空,不為空就不用去等待鎖了,這樣提高了效率。

      內(nèi)部類(lèi)創(chuàng)建外部類(lèi)實(shí)例

      該方式天然線程安全,是否final根據(jù)自己需要。
      1 /** 2 * 懶漢模式-線程安全,適用于多線程 3 * 在內(nèi)部類(lèi)被加載和初始化時(shí) 才創(chuàng)建實(shí)例 4 *
      靜態(tài)內(nèi)部類(lèi)不會(huì)自動(dòng)隨著外部類(lèi)的加載和初始化而初始化,它是要單獨(dú)加載和初始化的。 5 * 因?yàn)槭窃趦?nèi)部類(lèi)加載和初始化時(shí)創(chuàng)建的 因此它是線程安全的 6 */
      7 public class LazyInnerSingleton{ 8 private LazyInnerSingleton() { 9 } 10
      private static class Inner{ 11 private static final LazyInnerSingleton INSTANCE
      =new LazyInnerSingleton(); 12 } 13 public static LazyInnerSingleton
      getInstance(){14 return Inner.INSTANCE; 15 } 16 }
      ?

      總結(jié)

      餓漢模式

      * 靜態(tài)常量 簡(jiǎn)潔直觀容易理解
      * 枚舉 最簡(jiǎn)潔
      * 靜態(tài)代碼塊 可以在靜態(tài)塊里做一些初始化的工作
      懶漢模式

      * 單線程形式 該形式下不適用多線程,存在線程安全問(wèn)題
      * 多線程形式 適用于多線程
      * 內(nèi)部類(lèi)形式 最簡(jiǎn)潔
      ?

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問(wèn)題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          李美淑大尺度做爰视频 | 久久大陆 | 亚洲性爱综合 | 破外女出血一级毛片A片 | 超碰爆乳 | 亚洲一级国产 | 色哟哟一区二区三区四区 | 国产精品久久久久久AV下载网址 | 成人做爱视频www | 欧美顶级毛|