国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【設(shè)計(jì)模式】23種設(shè)計(jì)模式——單例模式(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn))

這篇具有很好參考價(jià)值的文章主要介紹了【設(shè)計(jì)模式】23種設(shè)計(jì)模式——單例模式(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn))。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

單例模式(Singleton)

介紹

  • 所謂類的單例設(shè)計(jì)模式,就是采取一定的方法,保證在整個(gè)的軟件系統(tǒng)中,對(duì)某個(gè)類只能存在一個(gè)對(duì)象實(shí)例,并且該類只提供一個(gè)取得其對(duì)象實(shí)例的方法(靜態(tài)方法)。
  • 比如Hibernate的SessionFactory,它充當(dāng)數(shù)據(jù)存儲(chǔ)源的代理,并負(fù)責(zé)創(chuàng)建Session對(duì)象。SessionFactory并不是輕量級(jí)的,一般情況下,一個(gè)項(xiàng)目通常只需要一個(gè)SessionFactory就夠,這是就會(huì)使用到單例模式。
  • 單例模式保證了系統(tǒng)內(nèi)存中該類只存在一個(gè)對(duì)象,節(jié)省了系統(tǒng)資源,對(duì)于一些需要頻繁創(chuàng)建銷毀的對(duì)象,使用單例模式可以提高系統(tǒng)性能
  • 當(dāng)想實(shí)例化一個(gè)單例類的時(shí)候,必須要記住使用相應(yīng)的獲取對(duì)象的方法,而不是使用new
  • 單例模式使用的場(chǎng)景:需要頻繁的進(jìn)行創(chuàng)建和銷毀的對(duì)象創(chuàng)建對(duì)象時(shí)耗時(shí)過(guò)多或耗費(fèi)資源過(guò)多(即:重量級(jí)對(duì)象),但又經(jīng)常用到的對(duì)象工具類對(duì)象、頻繁訪問(wèn)數(shù)據(jù)庫(kù)或文件的對(duì)象(比如數(shù)據(jù)源、session工廠等)

單例模式的八種寫法

  • 餓漢式(靜態(tài)常量)
  • 餓漢式(靜態(tài)代碼塊)
  • 懶漢式(線程不安全)
  • 懶漢式(線程安全,同步方法)
  • 懶漢式(線程安全,同步代碼塊)
  • 雙重檢查
  • 靜態(tài)內(nèi)部類
  • 枚舉

餓漢式(靜態(tài)常量)

步驟
  1. 構(gòu)造器私有化(防止new)
  2. 類的內(nèi)部創(chuàng)建對(duì)象
  3. 向外暴露一個(gè)靜態(tài)的公共方法
  4. 代碼實(shí)現(xiàn)
實(shí)現(xiàn)
package com.atguigu.singleton.type1;

public class SingletonTest01 {

   public static void main(String[] args) {
      //測(cè)試
      Singleton instance = Singleton.getInstance();
      Singleton instance2 = Singleton.getInstance();
      System.out.println(instance == instance2); // true
      System.out.println("instance.hashCode=" + instance.hashCode());
      System.out.println("instance2.hashCode=" + instance2.hashCode());
   }

}

//餓漢式(靜態(tài)變量)

class Singleton {
   
   //1. 構(gòu)造器私有化, 外部不能new
   private Singleton() {
      
   }
   
   //2.本類內(nèi)部創(chuàng)建對(duì)象實(shí)例
   private final static Singleton instance = new Singleton();
   
   //3. 提供一個(gè)公有的靜態(tài)方法,返回實(shí)例對(duì)象
   public static Singleton getInstance() {
      return instance;
   }
   
}

【運(yùn)行結(jié)果】

true
instance.hashCode=1554874502
instance2.hashCode=1554874502

Process finished with exit code 0

【分析】

  • 優(yōu)點(diǎn):這種寫法比較簡(jiǎn)單,就是在類裝載的時(shí)候就完成實(shí)例化。避免了線程同步問(wèn)題。
  • 缺點(diǎn):在類裝載的時(shí)候就完成實(shí)例化,沒(méi)有達(dá)到Lazy Loading的效果。如果從始至終從未使用過(guò)這個(gè)實(shí)例,則會(huì)造成內(nèi)存的浪費(fèi)
  • 這種方式基于classloader機(jī)制避免了多線程的同步問(wèn)題,不過(guò),instance在類裝載時(shí)就實(shí)例化,在單例模式中大多數(shù)都是調(diào)用get lnstance方法, 但是導(dǎo)致類裝載的原因有很多種,因此不能確定有其他的方式(或者其他的靜態(tài)方法) 導(dǎo)致類裝載,這時(shí)候初始化instance就沒(méi)有達(dá)到lazy loading的效果
  • 結(jié)論:這種單例模式可用,可能造成內(nèi)存浪費(fèi)

餓漢式(靜態(tài)代碼塊)

package com.atguigu.singleton.type2;

public class SingletonTest02 {

    public static void main(String[] args) {
        //測(cè)試
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2); // true
        System.out.println("instance.hashCode=" + instance.hashCode());
        System.out.println("instance2.hashCode=" + instance2.hashCode());
    }

}

//餓漢式(靜態(tài)變量)

class Singleton {

    //1. 構(gòu)造器私有化, 外部能new
    private Singleton() {

    }

    //2.本類內(nèi)部創(chuàng)建對(duì)象實(shí)例
    private static Singleton instance;

    static { // 在靜態(tài)代碼塊中,創(chuàng)建單例對(duì)象
        instance = new Singleton();
    }

    //3. 提供一個(gè)公有的靜態(tài)方法,返回實(shí)例對(duì)象
    public static Singleton getInstance() {
        return instance;
    }

}
static { // 在靜態(tài)代碼塊中,創(chuàng)建單例對(duì)象
    instance = new Singleton();
}

【分析】

  • 這種方式和上面的方式其實(shí)類似,只不過(guò)將類實(shí)例化的過(guò)程放在了靜態(tài)代碼塊中,也是在類裝載的時(shí)候,就執(zhí)行靜態(tài)代碼塊中的代碼,初始化類的實(shí)例。優(yōu)缺點(diǎn)和上面是一樣的
  • 結(jié)論:這種單例模式可用,但是可能造成內(nèi)存浪費(fèi)

懶漢式(線程不安全)

package com.atguigu.singleton.type3;


public class SingletonTest03 {

   public static void main(String[] args) {
      System.out.println("懶漢式1 , 線程不安全~");
      Singleton instance = Singleton.getInstance();
      Singleton instance2 = Singleton.getInstance();
      System.out.println(instance == instance2); // true
      System.out.println("instance.hashCode=" + instance.hashCode());
      System.out.println("instance2.hashCode=" + instance2.hashCode());
   }

}
class Singleton {
   private static Singleton instance;
   
   private Singleton() {}
   
   //提供一個(gè)靜態(tài)的公有方法,當(dāng)使用到該方法時(shí),才去創(chuàng)建 instance
   //即懶漢式
   public static Singleton getInstance() {
      if(instance == null) {
         instance = new Singleton();
      }
      return instance;
   }
}

【分析】

  • 起到了Lazy Loading的效果,但是只能在單線程下使用
  • 如果在多線程下,一個(gè)線程進(jìn)入了if (singleton == null)判斷語(yǔ)句塊,還未來(lái)得及往下執(zhí)行,另一個(gè)線程也通過(guò)了這個(gè)判斷語(yǔ)句,這時(shí)便會(huì)產(chǎn)生多個(gè)實(shí)例。所以在多線程環(huán)境下不可使用這種方式
  • 結(jié)論:在實(shí)際開(kāi)發(fā)中,不要使用這種方式

懶漢式(線程安全,同步方法)

package com.atguigu.singleton.type4;


public class SingletonTest04 {

    public static void main(String[] args) {
        System.out.println("懶漢式2 , 線程安全~");
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2); // true
        System.out.println("instance.hashCode=" + instance.hashCode());
        System.out.println("instance2.hashCode=" + instance2.hashCode());
    }

}
// 懶漢式(線程安全,同步方法)
class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    //提供一個(gè)靜態(tài)的公有方法,加入同步處理的代碼,解決線程安全問(wèn)題
    //即懶漢式
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

添加synchronized關(guān)鍵字,這樣子當(dāng)一個(gè)線程在執(zhí)行這個(gè)方法的時(shí)候,其他線程不能執(zhí)行這個(gè)方法

【分析】

  • 解決了線程不安全問(wèn)題
  • 效率太低了,每個(gè)線程在想獲得類的實(shí)例時(shí)候,執(zhí)行g(shù)etlnstance()方法都要進(jìn)行同步。而其實(shí)這個(gè)方法只執(zhí)行一次實(shí)例化代碼就夠了,后面的想獲得該類實(shí)例,直接return就行了。方法進(jìn)行同步效率太低
  • 結(jié)論:在實(shí)際開(kāi)發(fā)中,不推薦使用這種方式

懶漢式(線程安全,同步代碼塊)

class Singleton {
    private static Singleton instance;

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

【分析】

  • 這種方式,本意是想對(duì)第四種實(shí)現(xiàn)方式的改進(jìn),因?yàn)榍懊嫱椒椒ㄐ侍透臑橥疆a(chǎn)生實(shí)例化的的代碼塊
  • 但是這種同步并不能起到線程同步的作用。跟第3種實(shí)現(xiàn)方式遇到的情形一致,假如一個(gè)線程進(jìn)入了if(singleton == nul)判斷語(yǔ)句塊,還未來(lái)得及往下執(zhí)行另一個(gè)線程也通過(guò)了這個(gè)判斷語(yǔ)句,這時(shí)便會(huì)產(chǎn)生多個(gè)實(shí)例
  • 結(jié)論:在實(shí)際開(kāi)發(fā)中,不能使用這種方式

雙重檢查(推薦使用)

package com.atguigu.singleton.type6;


public class SingletonTest06 {

    public static void main(String[] args) {
        System.out.println("雙重檢查");
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2); // true
        System.out.println("instance.hashCode=" + instance.hashCode());
        System.out.println("instance2.hashCode=" + instance2.hashCode());

    }

}
class Singleton {
    //volatile:在Java中,volatile關(guān)鍵字可以保證變量的內(nèi)存可見(jiàn)性。
    //當(dāng)一個(gè)變量被聲明為volatile時(shí),編譯器和處理器會(huì)注意到這個(gè)變量可能會(huì)被其他線程并發(fā)地訪問(wèn)。
    //這樣可以避免線程之間的數(shù)據(jù)競(jìng)爭(zhēng),并確保多線程環(huán)境下變量的值是最新的。
    private static volatile Singleton instance;

    private Singleton() {
    }

    //提供一個(gè)靜態(tài)的公有方法,加入雙重檢查代碼,解決線程安全問(wèn)題, 同時(shí)解決懶加載問(wèn)題
    //同時(shí)保證了效率, 推薦使用
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

保證只有一個(gè)線程創(chuàng)建實(shí)例

synchronized (Singleton.class) {
    if (instance == null) {
        instance = new Singleton();
    }
}

【分析】

  • Double-Check概念是多線程開(kāi)發(fā)中常使用到的,如代碼中所示,我們進(jìn)行了兩次if (singleton == null)檢查,這樣就可以保證線程安全了
  • 這樣,實(shí)例化代碼只用執(zhí)行一次,后面再次訪問(wèn)時(shí),判斷if (singleton == null)直接return實(shí)例化對(duì)象,也避免的反復(fù)進(jìn)行方法同步
  • 線程安全;延遲加載;效率較高
  • 在實(shí)際開(kāi)發(fā)中,推薦使用這種單例設(shè)計(jì)模式

靜態(tài)內(nèi)部類(推薦使用)

package com.atguigu.singleton.type7;


public class SingletonTest07 {

   public static void main(String[] args) {
      System.out.println("使用靜態(tài)內(nèi)部類完成單例模式");
      Singleton instance = Singleton.getInstance();
      Singleton instance2 = Singleton.getInstance();
      System.out.println(instance == instance2); // true
      System.out.println("instance.hashCode=" + instance.hashCode());
      System.out.println("instance2.hashCode=" + instance2.hashCode());
   }

}
// 靜態(tài)內(nèi)部類完成, 推薦使用
class Singleton {
   
   //構(gòu)造器私有化
   private Singleton() {}
   
   //寫一個(gè)靜態(tài)內(nèi)部類,該類中有一個(gè)靜態(tài)屬性 Singleton
   private static class SingletonInstance {
      private static final Singleton INSTANCE = new Singleton(); 
   }
   
   //提供一個(gè)靜態(tài)的公有方法,直接返回SingletonInstance.INSTANCE
   public static Singleton getInstance() {
      return SingletonInstance.INSTANCE;
   }
}
private static class SingletonInstance {
  private static final Singleton INSTANCE = new Singleton(); 
}

【分析】

  • 當(dāng)加載類的時(shí)候,靜態(tài)內(nèi)部類是不會(huì)被加載的,調(diào)用getInstance()時(shí),靜態(tài)內(nèi)部類才會(huì)被裝載,而且只會(huì)裝載一次
  • 這種方式采用了類裝載的機(jī)制來(lái)保證初始化實(shí)例時(shí)只有一個(gè)線程
  • 靜態(tài)內(nèi)部類方式在Singleton類被裝載時(shí)并不會(huì)立即實(shí)例化,而是在需要實(shí)例化時(shí),調(diào)用getInstance方法,才會(huì)裝載Singletonlnstance類,從而完成Singleton的實(shí)例化
  • 類的靜態(tài)屬性只會(huì)在第一次加載類的時(shí)候初始化,所以在這里,JVM幫助我們保證了線程的安全性,在類進(jìn)行初始化時(shí),別的線程是無(wú)法進(jìn)入的
  • 優(yōu)點(diǎn):避免了線程不安全,利用靜態(tài)內(nèi)部類特點(diǎn)實(shí)現(xiàn)延遲加載,效率高
  • 結(jié)論:推薦使用

枚舉(推薦使用,而且很方便)

package com.atguigu.singleton.type8;

public class SingletonTest08 {
   public static void main(String[] args) {
      Singleton instance = Singleton.INSTANCE;
      Singleton instance2 = Singleton.INSTANCE;
      System.out.println(instance == instance2);
      
      System.out.println(instance.hashCode());
      System.out.println(instance2.hashCode());
      
      instance.sayOK();
   }
}
//使用枚舉,可以實(shí)現(xiàn)單例, 推薦
enum Singleton {
   INSTANCE; //屬性
   public void sayOK() {
      System.out.println("ok~");
   }
}

【運(yùn)行】

true
1554874502
1554874502
ok~

【分析】

  • 這借助JDK1.5中添加的枚舉來(lái)實(shí)現(xiàn)單例模式。不僅能避免多線程同步問(wèn)題,而且還能防止反序列化重新創(chuàng)建新的對(duì)象
  • 這種方式是Effective Java作者Josh Bloch 提倡的方式

單例模式在JDK中的應(yīng)用

【設(shè)計(jì)模式】23種設(shè)計(jì)模式——單例模式(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn)),java開(kāi)發(fā),設(shè)計(jì)模式,單例模式,java

聯(lián)系

案例:3例模式

【題目】

請(qǐng)編寫Triple類,實(shí)現(xiàn)最多只能生成3個(gè)Triple類的實(shí)例,實(shí)例編號(hào)分別為0,1,2且可以通過(guò)getInstance(int id)來(lái)獲取該編號(hào)對(duì)應(yīng)的實(shí)例(題目來(lái)源于《圖解設(shè)計(jì)模式》)

【代碼實(shí)現(xiàn)】

public class Triple {

    private static volatile Triple[] arr = new Triple[3];

    private Triple() {
    }

    public static Triple getInstance(int index) {
        if (index >= arr.length) {
            throw new RuntimeException("索引超出,示例數(shù)量只有" + arr.length + "個(gè)");
        }
        if (arr[index] == null) {
            synchronized (Triple.class) {
                if (arr[index] == null) {
                    arr[index] = new Triple();
                }
            }
        }
        return arr[index];
    }
}
public class TripleMain {
    public static void main(String[] args) {
        System.out.println("Start.");
        for (int i = 0; i < 9; i++) {
            Triple triple = Triple.getInstance(i % 3);
            System.out.println(i + ":" + triple);
        }
        System.out.println("End.");
    }
}

【運(yùn)行】

Start.
0:com.atguigu.singleton.A2.Triple@5cad8086
1:com.atguigu.singleton.A2.Triple@6e0be858
2:com.atguigu.singleton.A2.Triple@61bbe9ba
3:com.atguigu.singleton.A2.Triple@5cad8086
4:com.atguigu.singleton.A2.Triple@6e0be858
5:com.atguigu.singleton.A2.Triple@61bbe9ba
6:com.atguigu.singleton.A2.Triple@5cad8086
7:com.atguigu.singleton.A2.Triple@6e0be858
8:com.atguigu.singleton.A2.Triple@61bbe9ba
End.

文章說(shuō)明

本文章為本人學(xué)習(xí)尚硅谷的學(xué)習(xí)筆記,文章中大部分內(nèi)容來(lái)源于尚硅谷視頻(點(diǎn)擊學(xué)習(xí)尚硅谷相關(guān)課程),也有部分內(nèi)容來(lái)自于自己的思考,發(fā)布文章是想幫助其他學(xué)習(xí)的人更方便地整理自己的筆記或者直接通過(guò)文章學(xué)習(xí)相關(guān)知識(shí),如有侵權(quán)請(qǐng)聯(lián)系刪除,最后對(duì)尚硅谷的優(yōu)質(zhì)課程表示感謝。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-549314.html

到了這里,關(guān)于【設(shè)計(jì)模式】23種設(shè)計(jì)模式——單例模式(原理講解+應(yīng)用場(chǎng)景介紹+案例介紹+Java代碼實(shí)現(xiàn))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包