Java單例模式的幾種常見寫法
1.餓漢模式
餓漢模式也叫預(yù)加載模式,它是在類加載時直接創(chuàng)建并初始化單例對象,所以它并不存在線程安全的問題。它是依靠 ClassLoader 類機(jī)制,在程序啟動時只加載一次,因此不存在線程安全問題,它的實現(xiàn)代碼如下:
public class Singleton { // 1.防止外部直接 new 對象破壞單例模式 private Singleton() {} // 2.通過私有變量保存單例對象 private static Singleton instance = new Singleton(); // 3.提供公共獲取單例對象的方法 public static Singleton getInstance() { return instance; } }
優(yōu)點:實現(xiàn)簡單、不存在線程安全問題。 缺點:類加載時就創(chuàng)建了對象,創(chuàng)建之后如果沒被使用,就造成了資源浪費的情況。
2.懶漢模式
懶漢模式和餓漢模式正好是相反的,所謂的懶漢模式也就是懶加載(延遲加載),指的是它只有在第一次被使用時,才會被初始化,
它的實現(xiàn)代碼如下:
public class Singleton { // 1.防止外部直接 new 對象破壞單例模式 private Singleton() {} // 2.通過私有變量保存單例對象 private static volatile Singleton instance = null; // 3.提供公共獲取單例對象的方法 public static Singleton getInstance() { if (instance == null) { // 第一次效驗 synchronized (Singleton.class) { if (instance == null) { // 第二次效驗 instance = new Singleton(); } } } return instance; } }
懶漢模式使用的是雙重效驗鎖和 volatile 來保證線程安全的,從上述代碼可以看出,無論是餓漢模式還是懶漢模式,它們的實現(xiàn)步驟都是一樣的:
- 創(chuàng)建一個私有的構(gòu)造方法,防止其他調(diào)用的地方直接 new 對象,這樣創(chuàng)建出來的對象就不是單例對象了。
- 創(chuàng)建一個私有變量來保存單例對象。
- 提供一個公共的方法返回單例對象。
懶漢模式相比于餓漢模式來說,不會造成資源的浪費,但寫法要復(fù)雜一些。
3.靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類既能保證線程安全,又能保證懶加載,它只有在被調(diào)用時,才會通過 ClassLoader 機(jī)制來加載和初始化內(nèi)部靜態(tài)類,因此它是線程安全的,此模式的實現(xiàn)代碼如下:
public class Singleton { // 1.防止外部直接 new 對象破壞單例模式 private Singleton() { } // 2.靜態(tài)內(nèi)部類 private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } // 3.提供公共獲取單例對象的方法 public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
4.枚舉
枚舉也是在第一次被使用時,才會被 Java 虛擬機(jī)加載并初始化,所以它也是線程安全的,且是懶加載的,它的實現(xiàn)代碼如下:
public enum EnumSingleton { INSTANCE; public EnumSingleton getInstance(){ return INSTANCE; } }
總結(jié)
單例模式適用于經(jīng)常被訪問的對象,或是創(chuàng)建和銷毀需要調(diào)用大量資源和時間的對象,使用單例模式可以避免頻繁創(chuàng)建和銷毀對象。單例模式的常用實現(xiàn)方法有 4 種:餓漢模式、懶漢模式、靜態(tài)內(nèi)部類和枚舉。從寫法的簡潔性、線程安全性和代碼的易懂性等方面綜合來看,博主比較推薦使用枚舉或懶漢模式來實現(xiàn)單例模式。
到此這篇關(guān)于Java單例模式的幾種寫法的文章就介紹到這了,更多相關(guān)Java單例模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring實現(xiàn)動態(tài)修改時間參數(shù)并手動開啟關(guān)停操作
spring實現(xiàn)定時任務(wù)的方式有三種,分別是java自帶的timer類、spring task和quartz三種。本文只介紹spring自帶的task和第三方quartz,感興趣的朋友參考下吧2017-09-09java 實現(xiàn)通過 post 方式提交json參數(shù)操作
這篇文章主要介紹了java 實現(xiàn)通過 post 方式提交json參數(shù)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09Java對世界不同時區(qū)timezone之間時間轉(zhuǎn)換的處理方法
這篇文章主要介紹了Java對世界不同時區(qū)timezone之間時間轉(zhuǎn)換的處理方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07SpringCloud?Gateway詳細(xì)分析實現(xiàn)負(fù)載均衡與熔斷和限流
這篇文章主要介紹了SpringCloud?Gateway實現(xiàn)路由轉(zhuǎn)發(fā),負(fù)載均衡,熔斷和限流,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07spring-cloud入門之spring-cloud-config(配置中心)
這篇文章主要介紹了spring-cloud入門之spring-cloud-config(配置中心),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01關(guān)于scanner.nextInt()等next()和scanner.nextIine()連用注意事項
這篇文章主要介紹了關(guān)于scanner.nextInt()等next()和scanner.nextIine()連用注意事項,具有很好的參考價值,希望對大家有所幫助。2023-04-04java實現(xiàn)圖片轉(zhuǎn)ascii字符畫的方法示例
這篇文章主要介紹了java實現(xiàn)圖片轉(zhuǎn)ascii字符畫的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08如何在Spring Boot應(yīng)用中優(yōu)雅的使用Date和LocalDateTime的教程詳解
這篇文章主要介紹了如何在Spring Boot應(yīng)用中優(yōu)雅的使用Date和LocalDateTime,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07Java線程中斷機(jī)制interrupt、isInterrupted、interrupted方法詳解
這篇文章主要介紹了Java線程中斷機(jī)制interrupt、isInterrupted、interrupted方法詳解,一個線程不應(yīng)該由其他線程來強(qiáng)制中斷或停止,而是應(yīng)該由線程自己自行停止,所以,Thread.stop、Thread.suspend、Thread. resume都已經(jīng)被廢棄了,需要的朋友可以參考下2024-01-01