Java實(shí)現(xiàn)單例模式的五種方法介紹
餓漢式
立即加載
防止new對(duì)象,構(gòu)造私有,寫一個(gè)公共的方法返回對(duì)象
占用空間,線程安全
public class Singleton { /** * 私有構(gòu)造 */ private Singleton(){ System.out.println("構(gòu)造函數(shù)Singleton"); } private static Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; } }
懶漢式
延遲加載
占用空間小,效率有問題,線程不安全
public class Singleton { /** * 私有構(gòu)造 */ private Singleton(){ System.out.println("構(gòu)造函數(shù)Singleton"); } private static Singleton singleton = null; public static Singleton getInstance(){ if (singleton == null){ singleton = new Singleton(); } return singleton; } }
解決線程安全問題
在方法上加synchronized同步鎖或是用同步代碼塊對(duì)類加同步鎖,此種方式雖然解決了多個(gè)實(shí)例對(duì)象問題,但是該方式運(yùn)行效率卻很低下,下一個(gè)線程想要獲取對(duì)象,就必須等待上一個(gè)線程釋放鎖之后,才可以繼續(xù)運(yùn)行。
鎖太大
public class Singleton { /** * 私有構(gòu)造 */ private Singleton(){ System.out.println("構(gòu)造函數(shù)Singleton"); } private static Singleton singleton = null; public static synchronized Singleton getInstance(){ if (singleton == null){ singleton = new Singleton(); } return singleton; } }
雙重檢查鎖
提高同步鎖的效率
使用雙重檢查鎖進(jìn)一步做了優(yōu)化,可以避免整個(gè)方法被鎖,只對(duì)需要鎖的代碼部分加鎖,可以提高執(zhí)行效率。
第一個(gè)if判斷
第一個(gè)線程進(jìn)來new了Singleton,那么singleton就有值,第二個(gè)線程進(jìn)來,那么進(jìn)行第一個(gè)if判斷,不為null,直接返回,不用再去new了,提升了效率
第二個(gè)if判斷
兩個(gè)線程同時(shí)進(jìn)來,在synchronized,第一個(gè)線程進(jìn)入,另一個(gè)線程等待,第一個(gè)線程new Singleton,然后返回,另一個(gè)線程發(fā)現(xiàn)了第一個(gè)線程走了,進(jìn)入synchronized,如果不進(jìn)行if判斷,那么還會(huì)new Singleton,導(dǎo)致線程不安全
public class Singleton { /** * 私有構(gòu)造 */ private Singleton(){ System.out.println("構(gòu)造函數(shù)Singleton"); } private static Singleton singleton = null; public static synchronized Singleton getInstance(){ if (singleton == null){ //這個(gè)檢查是提高效率的 synchronized (Singleton.class){ if (singleton == null){ singleton = new Singleton(); //這個(gè)檢查是防止線程安全的 } } } return singleton; } }
靜態(tài)內(nèi)部類
這種方式引入了一個(gè)內(nèi)部靜態(tài)類(static class),靜態(tài)內(nèi)部類只有在調(diào)用時(shí)才會(huì)加載,它保證了Singleton 實(shí)例的延遲初始化,又保證了實(shí)例的唯一性。它把singleton 的實(shí)例化操作放到一個(gè)靜態(tài)內(nèi)部類中,在第一次調(diào)用getInstance() 方法時(shí),JVM才會(huì)去加載InnerObject類,同時(shí)初始化singleton 實(shí)例,所以能讓getInstance() 方法線程安全。
特點(diǎn)是:即能延遲加載,也能保證線程安全。
靜態(tài)內(nèi)部類雖然保證了單例在多線程并發(fā)下的線程安全性,但是在遇到序列化對(duì)象時(shí),默認(rèn)的方式運(yùn)行得到的結(jié)果就是多例的。
public class Singleton { /** * 私有構(gòu)造 */ private Singleton(){ } private static class InnerObject{ private static Singleton singleton = new Singleton(); } public static synchronized Singleton getInstance(){ return InnerObject.singleton; } }
內(nèi)部枚舉類實(shí)現(xiàn)
防止反射和反序列化攻擊
實(shí)上,通過Java反射機(jī)制是能夠?qū)嵗瘶?gòu)造方法為private的類的。這也就是我們現(xiàn)在需要引入的枚舉單例模式。
public class SingletonFactory { /** * 私有構(gòu)造 */ private enum EnumSingleton{ SINGLETON; private Singleton6 singleton; //枚舉類的構(gòu)造方法在類加載是被實(shí)例化 private EnumSingleton(){ singleton = new Singleton6(); } public Singleton6 getInstance(){ return singleton; } } public static Singleton6 getInstance(){ return EnumSingleton.SINGLETON.getInstance(); } } class Singleton6{ public Singleton6(){ } }
到此這篇關(guān)于Java實(shí)現(xiàn)單例模式的五種方法介紹的文章就介紹到這了,更多相關(guān)Java單例模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JAVA操作MongoDB數(shù)據(jù)庫實(shí)例教程
MongoDB是一個(gè)文檔型數(shù)據(jù)庫,是NOSQL家族中最重要的成員之一,下面這篇文章主要給大家介紹了關(guān)于JAVA操作MongoDB數(shù)據(jù)庫的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05利用java監(jiān)聽器實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)
過去使用ASP和ASP.NET兩種編程的時(shí)候,都寫過在線人數(shù)統(tǒng)計(jì)能,實(shí)現(xiàn)功能挺簡(jiǎn)單的!今天使用java來實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)有點(diǎn)另類,是通過Java監(jiān)聽器實(shí)現(xiàn)的,需要的朋友可以參考下2015-09-09Mybatis和Mybatis-Plus時(shí)間范圍查詢方式
這篇文章主要介紹了Mybatis和Mybatis-Plus時(shí)間范圍查詢方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Docker?DockerFile部署java?jar項(xiàng)目包及Mysql和Redis的詳細(xì)過程
Dockerfile是一種用于構(gòu)建Docker鏡像的文件格式,可以通過Dockerfile部署Java項(xiàng)目,這篇文章主要給大家介紹了關(guān)于Docker?DockerFile部署java?jar項(xiàng)目包及Mysql和Redis的詳細(xì)過程,需要的朋友可以參考下2023-12-12詳解使用Spring的BeanPostProcessor優(yōu)雅的實(shí)現(xiàn)工廠模式
這篇文章主要介紹了詳解使用Spring的BeanPostProcessor優(yōu)雅的實(shí)現(xiàn)工廠模式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07SpringBoot整合MybatisSQL過濾@Intercepts的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot整合MybatisSQL過濾@Intercepts的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Java實(shí)現(xiàn)對(duì)華北、華南、華東和華中四個(gè)區(qū)域的劃分
在Java中,通過定義枚舉類、編寫主程序和進(jìn)行測(cè)試,本文詳細(xì)介紹了如何劃分華北、華南、華東和華中四個(gè)區(qū)域,首先定義枚舉類標(biāo)識(shí)區(qū)域,然后通過主程序接收用戶輸入并返回相應(yīng)區(qū)域,最后通過測(cè)試用例確保正確性,文章還介紹了甘特圖和餅狀圖的使用2024-09-09Java序列化和反序列化_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
把對(duì)象轉(zhuǎn)換為字節(jié)序列的過程稱為對(duì)象的序列化,把字節(jié)序列恢復(fù)為對(duì)象的過程稱為對(duì)象的反序列化。接下來通過本文給大家介紹Java序列化和反序列化及主要的兩種用途,感興趣的的友參考下吧2017-05-05