java設(shè)計模式-單例模式實(shí)現(xiàn)方法詳解
單例模式,屬于創(chuàng)建類型的一種常用的軟件設(shè)計模式。通過單例模式的方法創(chuàng)建的類在當(dāng)前進(jìn)程中只有一個實(shí)例(根據(jù)需要,也有可能一個線程中屬于單例,如:僅線程上下文內(nèi)使用同一個實(shí)例)。就是采取一定的方法保證在整個的軟件系統(tǒng)中,對某個類只能存在一個對象實(shí)例,并且該類只提供一個取得其對象實(shí)例的方法(靜態(tài)方法)。
就是類在內(nèi)存中只能存在一個實(shí)例對象
餓漢式
所謂餓漢式,就是直接創(chuàng)建出類的實(shí)例化,然后用private私有化,對外只用靜態(tài)方法暴露。
靜態(tài)變量
步驟
- 構(gòu)造器私有化
- 類的內(nèi)部創(chuàng)建對象
- 向外暴露一個靜態(tài)的公共方法
優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|
寫法簡單,在類裝載的時完成實(shí)例化,避免了線程同步問題 | 類裝載時完成實(shí)例化,沒有達(dá)到LazyLoading的效果,若該實(shí)例從未使用,則會造成內(nèi)存浪費(fèi) |
class Singleton { //私有化構(gòu)造器 private Singleton() { } //內(nèi)部創(chuàng)建對象實(shí)例 private final static Singleton instance = new Singleton(); //對外公有的靜態(tài)方法 public static Singleton getInstance() { return instance; } }
靜態(tài)代碼塊
將類的實(shí)例化放到靜態(tài)代碼塊中的寫法,基本同上。
class Singleton { //靜態(tài)代碼塊 //私有化構(gòu)造器 private Singleton() {} //內(nèi)部創(chuàng)建對象實(shí)例 private static Singleton instance; static { // 在靜態(tài)代碼塊中,創(chuàng)建單例對象 instance = new Singleton(); } //對外公有的靜態(tài)方法 public static Singleton getInstance() { return instance; } }
測試代碼(后面都可使用這個測試代碼,不在贅述運(yùn)行截圖,可以自己試試):
public static void main(String[] args) { Singleton instance1 = Singleton.getInstance(); Singleton instance2 = Singleton.getInstance(); System.out.println(instance1 == instance2); System.out.println("instance1.hashCode=" + instance1.hashCode()); System.out.println("instance2.hashCode=" + instance2.hashCode()); }
懶漢式
所謂懶漢式,就是在需要調(diào)用的時候再創(chuàng)建類的實(shí)例化。
線程不安全
起到了懶加載效果,但是只能在單線程使用,多線程會不安全,因?yàn)楫?dāng)多個線程并發(fā)同時判斷instance為空時,就會相應(yīng)的實(shí)例化多個對象。
class Singleton { //線程不安全 private static Singleton instance; private Singleton() {} public static Singleton getInstance() { //調(diào)用時才實(shí)例化對象,懶漢式 if(instance == null) { instance = new Singleton(); } return instance; } }
線程安全
上面線程不安全,那上鎖不就好了,使用synchronized關(guān)鍵字。
這樣雖然解決了線程安全,但其實(shí)實(shí)例化操作只做一次,而獲取實(shí)例(即getInstance)的操作是很多次的,把調(diào)用的方法加上同步,會大大降低效率。
class Singleton { //線程安全 private static Singleton instance; private Singleton() {} //synchronized同步處理 public static synchronized Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
雙重檢查
上面代碼效率低,那在同步前判斷一下有沒有實(shí)例化不就好了,若沒有實(shí)例化則用同步方法new一個,否則直接return即可。即所謂的雙重檢查。
需要用到關(guān)鍵字volatile,防止指令重排。如果不用volatile關(guān)鍵字,就會和線程不安全情形一樣,在if判斷那會有并發(fā)。
class Singleton { //雙重檢查 private static volatile Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if(instance == null) { //判斷是否實(shí)例化 synchronized (Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; //否則直接return } }
這樣既實(shí)現(xiàn)了懶加載,又保證了線程安全。
靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類在外部類裝載時不會實(shí)例化,當(dāng)調(diào)用的時候才會裝載并實(shí)例化,且JVM保證了其裝載時的線程安全性。也能保證懶加載和線程安全,有點(diǎn)像自帶版的雙重檢查。
class Singleton { private static volatile Singleton instance; private Singleton() {} //靜態(tài)內(nèi)部類,包含一個靜態(tài)屬性:Singleton private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } //對外公有的靜態(tài)方法,直接返回SingletonInstance.INSTANCE public static synchronized Singleton getInstance() { return SingletonInstance.INSTANCE; } }
枚舉
其實(shí),使用枚舉也能實(shí)現(xiàn)單例模式,不僅能避免多線程同步問題,也能防止反序列化重新創(chuàng)建新的對象。
enum Singleton { INSTANCE; //屬性 public void say() { System.out.println("記得三連~"); } }
對應(yīng)測試:
public static void main(String[] args) { Singleton instance1 = Singleton.INSTANCE; Singleton instance2 = Singleton.INSTANCE; System.out.println(instance1 == instance2); System.out.println(instance1.hashCode()); System.out.println(instance2.hashCode()); instance1.say(); }
總結(jié)
單例模式使用的場景:
需要頻繁的進(jìn)行創(chuàng)建和銷毀的對象創(chuàng)建對象時耗時過多或耗費(fèi)資源過多(重量級對象)經(jīng)常用到的對象、工具類對象、頻繁訪問數(shù)據(jù)庫或文件的對象(數(shù)據(jù)源、session工廠)
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
spring boot thymeleaf 圖片上傳web項(xiàng)目根目錄操作步驟
這篇文章主要介紹了spring boot thymeleaf 圖片上傳web項(xiàng)目根目錄步驟,本文給大家提到了thymeleaf的基礎(chǔ)知識,需要的朋友可以參考下2018-03-03SpringBoot 接口開發(fā)教程(httpclient客戶端)
這篇文章主要介紹了SpringBoot 接口開發(fā)教程(httpclient客戶端),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03springboot配置文件屬性變量引用方式${}和@@用法及區(qū)別說明
這篇文章主要介紹了springboot配置文件屬性變量引用方式${}和@@用法及區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03springboot從application.properties中注入list,?map方式
這篇文章主要介紹了springboot從application.properties中注入list,map方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11java設(shè)計模式Ctrl?C和Ctrl?V的原型模式詳解
這篇文章主要為大家介紹了java設(shè)計模式Ctrl?C和Ctrl?V的原型模式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Spring Boot實(shí)現(xiàn)功能的統(tǒng)一詳解
這篇文章主要介紹了Spring Boot統(tǒng)一功能的處理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06