常见设计模式—单例模式(Singleton)
前言
好久沒寫東西了,但是想著無論什么事還是要堅持自己初心要堅持的東西。寫東西不能斷!
對于常用的23種設計模式,這里筆者會根據(jù)自己學習和出現(xiàn)頻率、重要程度進行學習記錄吧。并且每種設計模式可能會根據(jù)暫時需求側重學習深淺。
單例模式
有很多直接把單例分成很多種,這里我就分兩個大類(餓漢懶漢)在這里說啦。
單例模式(Singleton Pattern)是設計模式中最簡單的模式之一,屬于創(chuàng)建型模式。這種設計模式主要是類的對象只有一個實例,不需要每次new 創(chuàng)造。而我們要做的的就是確保這個對象創(chuàng)建的唯一。然后根據(jù)一些特征進行優(yōu)化創(chuàng)建以及訪問改類。
而單例模式也有很多的應用,比如很多驅(qū)動例如攝像頭、打印機等等,而在javaweb中的spring有很多配置文件,掌控全局,同樣也是單例的。
對于單例,主要是全局只有這么一個對象。對了它的理解,這里筆者打幾個有可能不太恰當?shù)睦斫?#xff0c;目的在于幫助理解記憶,如果有錯誤還請指正。
個人可能不太恰當?shù)睦斫?/strong>:
- 一定程度上單例模式和普通的模式有可能是一根根火柴和打火機的差別。火柴想燃燒每次都要一根火柴摩擦燃燒為灰燼作為代價。而一個打火機可以持續(xù)供給。同樣如果你只想在某個線程某個類想要得到執(zhí)行改類的一個方法,如果這個類占用的內(nèi)存、空間巨大,耗費的時間也很大的話,如果頻繁創(chuàng)造是一筆很大的負擔,那樣就不如咱們就創(chuàng)建好一個然后供我們使用就好啦。
- 一定程度又像是他人和個人的區(qū)別。每個人都可能干過相同的事情,可能很多人都在校園的跑道上跑過步,但他們并不是你,你也可能在操場上跑過很多圈。但只有你知道你的思考。同樣單例模式在一定程度可以看作一個人生,它可能有很多職能,也可能干過很多事、重復過很多事。但它可能對自己有從始至終的思考和記錄。它可能有些全局參數(shù)記錄著程序從始至終一些狀態(tài)、信息等等。也就是它一直是它,你也一直是你獨特的自己。
- 其他等等
至于單例模式的優(yōu)缺點,這里就不作詳細介紹了。無非是關于性能職能、時間、空間、拓展性等方面的一些討論。這個可以參考不同人的不同理解。本文主要記錄單例模式的實現(xiàn)方面。而同樣單例模式實現(xiàn)上分為餓漢式和懶漢式:
單例模式創(chuàng)建要求:
- 某個類只能有一個實例(構造器私有化)
- 它必須自行創(chuàng)建這個實例(含有一個改類的靜態(tài)變量來保存這個唯一的實例)
- 自行向整個系統(tǒng)提供這個實例(直接暴露或者用靜態(tài)變量的get方法)
餓漢式
直接創(chuàng)建對象,不存在線程安全問題 。對于餓漢式的實現(xiàn)是相對簡單和容易的。在實際遇到這種類似的思想其實也很多。
理解:
- 這個餓漢式就好比雙十一,你一下把你家里感覺可能缺的日后可能需要(也不一定需要的)全部給買了。比如啥洗衣液屯、棉衣棉鞋棉被日后可能要買也買。然后啥微波爐、烤箱我感覺可能以后會用我也買買買。買買買。這一下就買全了。但是:
- 同樣在實際的生產(chǎn),我們一個項目中可能有很多這樣單例的存在,如果一次性啟動的話對時間花銷真的是太大。可能對程序的壓力和體驗都很差。所以一般很少直接使用。這種體驗,像極了你打開某個網(wǎng)頁等待JavaScript和css的過程。
餓漢式的幾種實現(xiàn)方式:
01 . 直接實例化餓漢式(簡潔直觀)
02 . 枚舉式(最簡潔)
public enum singleton2 {INSTANCE }03 . 靜態(tài)代碼塊餓漢式(適合復雜實例化)
public class singleton3 {public static final singleton3 INSTANCE;static {/**** 有可能一些數(shù)據(jù)需要配置,需要從類加載器加載* 例如從某xxx.properties加載某些配置信息,我們只需更改配置文件不需要更改代碼*/INSTANCE=new singleton3();}private singleton3(){} }懶漢式
我們知道餓漢式在早早把對象創(chuàng)建好,在執(zhí)行一些其他邏輯時候不存在線程安全的問題。但是懶漢式就不一樣啦,延遲創(chuàng)建對象可能會有線程安全問題。
01 .線程不安全(適合單線程)
對于這種單線程沒問題,但是如果如果兩個或多個線程來同時訪問instance如果都為null同時申請的時候會遇到下圖等之類問題,這違背了單例模式的設計原則并且可能會對系統(tǒng)數(shù)據(jù)造成錯誤。
02 .線程安全(適用于多線程)
怎么優(yōu)化上述的懶漢式單例模式呢?既然不允許多個線程這樣同時訪問,那么咱們給它上個鎖不久行了嘛!
但是這樣有啥問題呢?就是我獲取這個單例對象的時候,被上鎖了。你氣不氣?我們就是在創(chuàng)建這個單例時候多線程可能出現(xiàn)點問題,咱么獲取的時候不存在線程安全問題啊。。你為啥獲取也要鎖??
這就好比,咱們都喜歡看美女,跟美女說話要排隊一個一個來,只能一個在一個時刻,但是你看美女不需要排隊啊!!!
03 .線程安全推薦版(適用于多線程)
對于上述存在的問題,咱們只需要雙重判定就行了。
- 首先判斷instance是不是為null。如果不是null說明被實例化過直接返回即可!nice!
- 如果instance為null?上鎖之后再判空實例化。
兩個判斷為null?為啥要兩個?
- 第一個:用來判斷是否為空需要上鎖new 實例。
- 第二個:上鎖后雖然只有一個會執(zhí)行當前方法,但是很可能都為null的時候兩個或多個都為null上鎖的想構造。然后后面線程在等待同時前面線程構造好了,那么它就不需要再去構造這個instance啦!直接不操作就行了。
就這樣,稍微完美的方法就這樣產(chǎn)生了。
04 .靜態(tài)內(nèi)部類形式(適用于多線程)
上面的方法可能有些復雜,而靜態(tài)內(nèi)部類也是個好方式。主要是靜態(tài)內(nèi)部類和外部類不是一起加載的,并且你去調(diào)用它的時候他就會初始化,并且類加載是線程安全的,這個不需要考慮線程安全問題。當加載完之后你就可以直接拿啦。這樣也能達到延遲加載的作用。
這個更詳細你可以自己研究靜態(tài)變量(類變量)、靜態(tài)內(nèi)部類等等加載順序,研究下`static關鍵字。
public class singleton7 {private singleton7(){}private static class inner{private static final singleton7 instance=new singleton7();}public static singleton7 getInstance(){return inner.instance;} }結語
學習參考尚學堂單例講解以及百科、菜鳥教程等等,有些區(qū)別但是大部分實現(xiàn)都是相似的,帶上個人理解分享給大家。如果有問題和疏漏還請指教!
歡迎交流學習、歡迎關注微信公眾號:bigsai
總結
以上是生活随笔為你收集整理的常见设计模式—单例模式(Singleton)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈迷宫搜索类的双向bfs问题(例题解析
- 下一篇: 玩转服务器(华为云)—购买配置登录篇