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