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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一人一猫旅行记之浅析单例模式

發布時間:2023/12/16 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一人一猫旅行记之浅析单例模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

單例模式是我們日常工作中接觸最多,也可以說是最簡單的一個設計模式。那么什么是單例呢?為什么要用這種模式?
單例簡單來說就是只進行一次初始化,以Imageloader為解釋為什么要用這種模式,因為ImageLoader會涉及到大量的io和網絡請求,消耗大量的資源,為了減少資源的消耗和浪費,便出現了單例模式。
我們常見的單例模式有很多種實現方式,比如餓漢模式、懶漢模式、雙加鎖模式等等,下面以簡單的例子來一一記錄這些單例模式的實現:
1、餓漢模式
為何稱之為“餓漢模式”呢?因為餓漢經常會突然的餓意襲來,為了在餓意到來的時候,有足夠的食物,餓漢需要提前將食物準備好。我們的“餓漢模式”也是這樣,在使用之前便為我們初始化了單例對象,需要注意的是初始化的時候,還沒有產生子線程,因此不會存在線程安全的問題。

public class Hungry {private static Hungry INSTANCE = new Hungry();private Hungry(){}public static Hungry getInstance(){return INSTANCE;} }

2、懶漢模式
該模式是經常與餓漢一起提起的,為什么叫懶漢呢?是因為該模式下不會提前進行初始化,而是在需要的時候才會進行初始化。在這種模式下,需要注意的是高并發情況下,會出現線程安全問題,因此需要引入同步鎖!

public class Lazy {private static Lazy INSTANCE = null;private Lazy(){}public static synchronized Lazy getInstance(){if(INSTANCE == null){INSTANCE = new Lazy();}return INSTANCE;} }

“餓漢模式”與“懶漢模式”的區別在于初始化的時間不同,“餓漢模式”下無論是否會調用,都會進行初始化,造成資源的浪費,而“懶漢模式”只會在需要的時候初始化,不會造成資源浪費。
3、雙加鎖(DCL)模式
在“懶漢模式”,雖然不會每次調用getInstance都會進行初始化,但是每次調用都會使用同步鎖,也會造成不必要的浪費,因此出現了“雙加鎖模式”,代碼如下:

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

從上面的代碼,我們可以看到兩次判空操作,第一次判空是為了判斷是否需要加鎖,而第二次判斷則是為了保證只會初始化一次。這么看來,這種模式是不是一種最優的方案呢?實際上是不支持這種寫法的,因為會有一個叫做“重排序”的問題,重排序通常是編譯器或運行時環境為了優化程序性能而采取的對指令進行重新排序執行的一種手段。
正常情況下,INSTANCE = new DoubleCheckLocked();這句代碼可以分為三個步驟:
a.分配對象的內存空間
b.初始化對象
c.設置sInstance指向剛分配的內存地址
但是由于重排序的存在,在高并發的環境下,為了提高運行速率,可能會讓bc的步驟發生變化,這樣就有可能導致某個線程調用獲取到了一個還未初始化的對象。
JDK1.5之后針對上面的問題,官方對volatile進行了優化,因此在1.6之后也可以通過volatile實現。
4、靜態內部類實現單例

public class StaticInnerClass {private StaticInnerClass(){}public static StaticInnerClass getInstance(){return SingleClass.INSTANCE;}private static class SingleClass{private static final StaticInnerClass INSTANCE = new StaticInnerClass();} }

因為INSTANCE 的定義是private static final,因此只會在第一次調用的時候才會初始化,因此不會涉及線程安全問題。另外外部類加載的時候并不會進行初始化,因此不會占用內存。

當然除了上面四種方式,我們還可以通過枚舉或者一些容器,如HashMap等實現單例,枚舉無需解釋,本身枚舉就是為單例而生,而使用容器等可能會涉及到線程安全問題,在某些場景下使用需要思考清楚。
5、枚舉實現單例

public class Enum {public enum EnumEnum{ENUM;private EnumEnum(){INSTANCE = new Enum();}private Enum INSTANCE;public Enum getINSTANCE(){return INSTANCE;}}private Enum(){}public static Enum getInstance(){return EnumEnum.ENUM.getINSTANCE();} }

6、容器實現單例

public class Container {private static Map<String,Container> SINGLEMAP = new HashMap<>();public static void putSingle(String key,Container value){if(!SINGLEMAP.containsKey(key)){SINGLEMAP.put(key,value);}}public static Container getInstance(String key){return SINGLEMAP.get(key);} }

綜上所述,實現單例的方法有很多種,其核心就是為了減少初始化的次數,從而減少資源的浪費,多用在涉及到IO、網絡請求等場景。道路千萬條,針對不同的場景,選擇最合適的方案!

總結

以上是生活随笔為你收集整理的一人一猫旅行记之浅析单例模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。