日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【秒懂设计模式】单例设计模式

發(fā)布時(shí)間:2025/3/15 asp.net 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【秒懂设计模式】单例设计模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?秒懂設(shè)計(jì)模式——單例設(shè)計(jì)模式


(三)單例設(shè)計(jì)模式

1.先解釋一下,什么是單例模式呢?

Java中是這樣定義的:“一個(gè)類有且僅有一個(gè)實(shí)例,并且自行實(shí)例化向整個(gè)系統(tǒng)提供。

顯然從單例模式的定義中,我們可以發(fā)現(xiàn)它有三個(gè)要點(diǎn)

①某個(gè)類只能有一個(gè)實(shí)例;

②它必須自行創(chuàng)建這個(gè)實(shí)例;

③它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。

2.要滿足這三個(gè)要點(diǎn),應(yīng)該如何實(shí)現(xiàn)呢?下面讓我們來逐條分析:

①如何保證某個(gè)類只能有一個(gè)實(shí)例?

讓我先來想一下,一個(gè)類的對象是如何創(chuàng)建的呢?答案是:一個(gè)類的對象的產(chǎn)生是由類構(gòu)造函數(shù)來完成。那么,我們是不是可以通過私有類構(gòu)造函數(shù)來實(shí)現(xiàn)呢?

②如何保證類定義中含有一個(gè)該類的靜態(tài)私有對象?

這個(gè)就很簡單了,讓單例類自己創(chuàng)建自己的唯一實(shí)例

③如何保證它自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例?

這個(gè)也不難,對外提供獲取此對象的靜態(tài)方法即可。

3.單例模式分為幾種呢?

①懶漢式,線程不安全;

②懶漢式,線程安全;

③餓漢式;

④雙檢鎖/雙重校驗(yàn)鎖(DCL,即 double-checked locking);

⑤登記式/靜態(tài)內(nèi)部類;

⑥枚舉式;

下面仍然通過一個(gè)故事,逐一介紹這幾種類型的單例模式,并且在最后,還會(huì)分析一下他們的性能差異。

【講故事】某野雞大學(xué)(),只有一個(gè)學(xué)生會(huì)主席(唯一對象,自行實(shí)例化),還是一個(gè)漂亮妹子叫“M蓉”,其他附近野鴨大學(xué)的學(xué)長都喜歡請她去自己宿舍,連夜補(bǔ)習(xí)英語(向整個(gè)系統(tǒng)提供實(shí)例)。

1)懶漢式,線程不安全

先解釋一下為什么叫懶漢式:“懶”顧名思義就是延遲,懶漢式就是指,只有在獲取此單例對象時(shí),才會(huì)去創(chuàng)建此對象

Java代碼】

①創(chuàng)建一個(gè)單例模式的類。

package com.liyan.lazy; /*** 懶漢式的M蓉(線程不安全)* <p>Title: LazyMRong</p> * @author Liyan * @date 2017年4月27日 下午2:00:44*/ public class LazyMRong {//1.私有空參構(gòu)造,防止別人創(chuàng)建private LazyMRong(){}//2.自己創(chuàng)建自己的唯一實(shí)例private static LazyMRong lazyMRong ;//3.對外提供獲取此對象的靜態(tài)方法public static LazyMRong getLazyMRong() {if (lazyMRong == null) {//懶漢式意味著,只有你在想獲取時(shí),才創(chuàng)建此對象return new LazyMRong();}return lazyMRong;}public void teachEnglish() {System.out.println("連夜補(bǔ)習(xí)外語!");} }

②創(chuàng)建外部訪問

package com.liyan.lazy; /*** S喆請M蓉補(bǔ)習(xí)外語* <p>Title: SZhe</p> * @author Liyan * @date 2017年4月27日 下午2:15:23*/ public class SZhe {public static void main(String[] args) {//通過靜態(tài)方法,獲取到單例對象LazyMRong lazyMRong = LazyMRong.getLazyMRong();//調(diào)用補(bǔ)習(xí)外語方法lazyMRong.teachEnglish();} }

分析:首先懶漢式肯定是延遲初始化的,但是不支持多線程。因?yàn)?strong>沒有加鎖synchronized,所以有些資料上認(rèn)為,從嚴(yán)格意義上講,它并不算單例模式

2)懶漢式,線程安全

這個(gè)跟上面的懶漢式,線程不安全,唯一的區(qū)別就是:在獲取單例類的靜態(tài)方法上,加上了synchronized關(guān)鍵字進(jìn)行修飾

package com.liyan.lazy; /*** 懶漢式的M蓉(線程安全)* <p>Title: LazyMRong</p> * @author Liyan * @date 2017年4月27日 下午2:00:44*/ public class LazyMRong {//1.私有空參構(gòu)造,防止別人創(chuàng)建private LazyMRong(){}//2.聲明自己的唯一實(shí)例,先不實(shí)例化private static LazyMRong lazyMRong ;//3.對外提供獲取此對象的靜態(tài)方法public synchronized static LazyMRong getLazyMRong() {if (lazyMRong == null) {//懶漢式意味著,只有你在想獲取時(shí),才創(chuàng)建此對象return new LazyMRong();}return lazyMRong;}public void teachEnglish() {System.out.println("連夜補(bǔ)習(xí)外語!");} }

3)餓漢式分析:毋庸置疑,它是延遲初始化的,能夠在多線程中很好的工作,同時(shí)在第一次調(diào)用時(shí),才進(jìn)行初始化,避免了內(nèi)存的浪費(fèi)。但是加了synchronized 鎖機(jī)制,所以效率很低

先解釋一下為什么叫餓漢式:“餓”意味著“著急”,餓漢式就是指,不管單例對象有沒有外部訪問,先實(shí)例化再說

Java代碼】餓漢式的M蓉

package com.liyan.hungry; /*** 餓漢式的M蓉(線程安全)* <p>Title: HungryMRong</p> * @author Liyan * @date 2017年4月27日 下午3:02:18*/ public class HungryMRong {//1.私有空參構(gòu)造,防止別人創(chuàng)建private HungryMRong(){}//2.創(chuàng)建自己的唯一對象,并直接實(shí)例化(餓漢式,因?yàn)轲I著急,不管三七二十一,直接實(shí)例化)private static HungryMRong hungryMRong = new HungryMRong();//3.對外提供獲取此對象的靜態(tài)方法public static HungryMRong getHungryMRong() {return hungryMRong;} }

4)雙重檢查鎖(DCL,即 double-checked locking)分析:顯然餓漢式,不懶,所以沒有延遲初始化,同時(shí)它基于 classloder 機(jī)制,而沒用加鎖的方式,所以既避免了多線程的同步問題,又使得執(zhí)行效率得到提高。但是,因?yàn)樗陬惣虞d時(shí)就初始化,所以會(huì)造成內(nèi)存的浪費(fèi)

先解釋一下為什么叫雙重檢查鎖:顧名思義,會(huì)涉及到兩把鎖:

①進(jìn)入方法過后,先檢查實(shí)例是否存在,如果不存在才進(jìn)入下面的同步塊;

②進(jìn)入同步塊后,再次檢查實(shí)例是否存在,如果不存在,就在同步的情況下創(chuàng)建該實(shí)例。

Java代碼】雙重檢查鎖的M蓉

package com.liyan.dcl; /*** DCL雙重檢查鎖的單例模式的M蓉* <p>Title: DCLMrong</p> * @author Liyan * @date 2017年4月27日 下午4:54:30*/ public class DCLMrong {//1.私有空參構(gòu)造,防止別人創(chuàng)建private DCLMrong (){}//2.聲明唯一的單例對象;注意這里用到了volatile關(guān)鍵字!private volatile static DCLMrong dclMrong ;//3.對外提供獲取此對象的靜態(tài)方法public static CLMrong getDclMrong() {//第一把鎖:先檢查實(shí)例是否存在,如果不存在才進(jìn)入下面的同步塊;if (dclMrong == null) {synchronized (DCLMrong.class) {//第二把鎖:再次檢查實(shí)例是否存在,如果不存在,就在同步的情況下創(chuàng)建一個(gè)實(shí)例。if (dclMrong == null) {return new DCLMrong();}}}return dclMrong;} }

分析:這種方式采用雙鎖機(jī)制,安全且在多線程情況下能保持高性能說明:?雙重檢查加鎖機(jī)制的實(shí)現(xiàn)會(huì)使用一個(gè)關(guān)鍵字volatile,它的意思是:volatile修飾的變量的值,將不會(huì)被本地線程緩存,所有對該變量的讀寫都是直接操作共享內(nèi)存,從而確保多個(gè)線程能正確的處理該變量

5)登記式/靜態(tài)內(nèi)部類

先解釋一下為什么叫登記式:見名知意,想要獲取某單例對象,沒登記的必須先登記,然后才能獲取。此時(shí)我們還需要一個(gè)登記簿(Map集合),當(dāng)然,這個(gè)登記簿可以記錄一堆單例對象,而不僅僅是一個(gè)。

這個(gè)模式確實(shí)復(fù)雜了一些,而且很多網(wǎng)上的例子也是覺得有所不妥,我根據(jù)個(gè)人理解,寫了如下的代碼,如果各位看官覺得也有疑問,歡迎留言討論。

Java代碼】

①創(chuàng)建登記式單例模式類

package com.liyan.register; import java.util.HashMap; import java.util.Map; /*** 登記式單例模式* <p>Title: RegisterMrong</p> * @author Liyan * @date 2017年4月27日 下午6:38:22*/ public class RegSingleton {//1.私有空參構(gòu)造,防止別人創(chuàng)建private RegSingleton(){}//2.創(chuàng)建一個(gè)登記簿,在靜態(tài)代碼塊中創(chuàng)建自己的唯一對象private static Map<String, RegSingleton> map = new HashMap<String, RegSingleton>(0); //在登記簿上登記private static void singletonHolder(String name) {if(name==null){ name="RegSingleton"; } RegSingleton singleton = new RegSingleton(); //利用反射獲取類名,并作為map集合的keymap.put(name, singleton);System.out.println("已將"+ name +"記錄到登記簿!");}//3.對外提供獲取此對象的靜態(tài)方法public static RegSingleton getInstance(String name){ if(name==null){ name="RegSingleton"; System.out.println("名字為空,自動(dòng)找RegSingleton!");} //查詢登記簿上是否登記過if(map.get(name)==null){ System.out.println("名字"+name+"未在登記簿中登記!");try { //如果沒有登記過,則先進(jìn)行登記System.out.println("名字"+name+"開始在登記簿中登記!");RegSingleton.singletonHolder(name);//登記之后再返回該對象System.out.println("名字"+name+"已經(jīng)登記完成!");return map.get(name);} catch (Exception e) { e.printStackTrace(); } }else {//如果登記過,直接返回該單實(shí)例System.out.println("名字"+name+"之前在登記簿中登記過了!");return map.get(name); }return null;} public void teachEnglish() {System.out.println("連夜補(bǔ)習(xí)外語!");} }

②創(chuàng)建外部訪問

package com.liyan.register; /*** S喆請M蓉補(bǔ)習(xí)外語* <p>Title: SZhe</p> * @author Liyan * @date 2017年4月27日 下午2:15:23*/ public class SZhe {public static void main(String[] args) {RegSingleton mrong = RegSingleton.getInstance("Mrong");mrong.teachEnglish();} }

③結(jié)果

名字Mrong未在登記簿中登記! 名字Mrong開始在登記簿中登記! 已將Mrong記錄到登記簿! 名字Mrong已經(jīng)登記完成! 連夜補(bǔ)習(xí)外語!

①相同點(diǎn):都利用ClassLoder機(jī)制,來保證初始化時(shí)只有一個(gè)線程。分析:主要是比較一下,登記模式和雙重檢驗(yàn)鎖式有何異同?

②不同點(diǎn):雙重檢驗(yàn)鎖式在類一被裝載是就被初始化了,所以它沒有延遲的效果;而登記模式,只有再主動(dòng)調(diào)用獲取該對象的靜態(tài)方法時(shí),才被初始化,所以它有延遲效果。

6)枚舉式

先解釋一下為什么叫枚舉式:不僅能避免多線程同步問題,而且還自動(dòng)支持序列化機(jī)制,防止反序列化重新創(chuàng)建新的對象,絕對防止多次實(shí)例化。不過,由于 JDK1.5 之后才加入 enum 特性,用這種方式寫不免讓人感覺生疏,但是《Effective Java》一書中的話有這樣一段很經(jīng)典的話:“單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法!

Java代碼】枚舉單例模式的M蓉

package com.liyan.enummodel; /*** 枚舉單例模式的M蓉* <p>Title: EnumMrong</p> * @author Liyan * @date 2017年4月27日 下午9:23:59*/ public class EnumMrong {//1.私有空參構(gòu)造,防止別人創(chuàng)建private EnumMrong() {}//2.申明自己的唯一對象public static EnumMrong getInstance() {return Singleton.INSTANCE.getInstance();}//3.對外提供獲取此對象的靜態(tài)方法private static enum Singleton {INSTANCE;private EnumMrong singleton;//在構(gòu)造方法中實(shí)例化對象,保證只調(diào)用一次private Singleton() {singleton = new EnumMrong();}public EnumMrong getInstance() {return singleton;}} }


?
?

總結(jié)

以上是生活随笔為你收集整理的【秒懂设计模式】单例设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。