日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

java單例模式實現的方法

瀏覽:31日期:2022-08-31 17:53:06

1.最基本的單例模式

/** * @author LearnAndGet * @time 2018年11月13日 * 最基本的單例模式 */public class SingletonV1 { private static SingletonV1 instance = new SingletonV1();; //構造函數私有化 private SingletonV1() {} public static SingletonV1 getInstance() { return instance; }}

import org.junit.Test;public class SingletonTest { @Test public void test01() throws Exception { SingletonV1 s1 = SingletonV1.getInstance(); SingletonV1 s2 = SingletonV1.getInstance(); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); }}//運行結果如下:589873731589873731

2.類加載時不初始化實例的模式

上述單例模式在類加載的時候,就會生成實例,可能造成空間浪費,如果需要修改成,在需要使用時才生成實例,則可修改代碼如下:

public class SingletonV2 { private static SingletonV2 instance; //構造函數私有化 private SingletonV2() {} public static SingletonV2 getInstance() { if(instance == null) { instance = new SingletonV2();} return instance; } }

然而,上述方案雖然在類加載時不會生成實例,但是存在線程安全問題,如果線程A在執行到第10行時,線程B也進入該代碼塊,恰好也執行好第10行,此時如果實例尚未生成,則線程A和線程B都會執行第12行的代碼,各自生成一個實例,此時就違背了單例模式的設計原則。實際測試代碼如下:

public class SingletonTest { @Test public void test02() throws Exception { for(int i=0;i<1000;i++) { Thread th1 = new getInstanceThread(); th1.start(); } } class getInstanceThread extends Thread { public void run() { try { SingletonV2 s = SingletonV2.getInstance(); System.out.println(Thread.currentThread().getName()+' get Instance '+s.hashCode()+' Time: '+System.currentTimeMillis()); }catch(Exception e) { e.printStackTrace(); } } } }

經過多次測試,可能產生如下輸出結果:

java單例模式實現的方法

3.線程安全的單例模式

在上述單例模式下進行改進,在getInstance方法前加入 Sychronized關鍵字,來實現線程安全,修改后代碼如下:

public class SingletonV3 { private static SingletonV3 instance; //構造函數私有化 private SingletonV3() {} //synchronized關鍵字在靜態方法上,鎖定的是當前類: public static synchronized SingletonV3 getInstance() { if(instance == null) { instance = new SingletonV3(); } return instance; } }

增加sychronized關鍵字后,確實能夠改善線程安全問題,但是也帶來了額外的鎖開銷。性能受到一定影響。舉例來說,此時如果有1000個線程都需要使用SingletonV3實例,因為加鎖的位置在getInstance上,因此,每個線程都必須等待其他獲取了鎖的線程完全執行完鎖中的方法后,才能夠進入該方法并獲取自己的實例。

4.雙重校檢+線程安全單例模式

于是可以在上述代碼的基礎上,只有當Singleton實例未被初始化時,對實例化方法加鎖即可。在Singleton實例已經被初始化時,無需加鎖,直接返回當前Singleton對象。代碼如下:

private static SingletonV4 instance; //構造函數私有化 private SingletonV4() {} public static SingletonV4 getInstance() { if(instance == null) { synchronized(SingletonV4.class) { //雙重校檢 if(instance == null) { instance = new SingletonV4(); } } } return instance; }

5.內部類單例模式 

盡管上述方案解決了同步問題,雙重校檢也使得性能開銷大大減小,但是,只有有synchronized關鍵字的存在。性能多多少少還是會有一些影響,此時,我們想到了 '內部類'的用法。

①.內部類不會隨著類的加載而加載

②.一個類被加載,當且僅當其某個靜態成員(靜態域、構造器、靜態方法等)被調用時發生。

靜態內部類隨著方法調用而被加載,只加載一次,不存在并發問題,所以是線程安全。基于此,修改代碼如下:

public class SingletonV5 { //構造函數私有化 private SingletonV5() {} static class SingetonGet { private static final SingletonV5 instance = new SingletonV5(); } public static SingletonV5 getInstance() { return SingetonGet.instance; } }

6.反射都不能破壞的單例模式

靜態內部類實現的單例模式,是目前比較推薦的方式,但是在java功能強大反射的機制下,它就是個弟弟,此時利用反射仍然能夠創建出多個實例,以下是創建實例的代碼:

@Test public void test4() { //普通方式獲取實例s1,s2 SingletonV5 s1 = SingletonV5.getInstance(); SingletonV5 s2 = SingletonV5.getInstance(); //利用反射獲取實例s3,s4 SingletonV5 s3 = null; SingletonV5 s4 = null; try { Class<SingletonV5> clazz = SingletonV5.class; Constructor<SingletonV5> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); s3 = constructor.newInstance(); s4 = constructor.newInstance(); }catch(Exception e) { e.printStackTrace(); } System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(s3.hashCode()); System.out.println(s4.hashCode()); }

輸出結果如下:

5898737315898737312000064062052001577

可以看到,s1和s2擁有相同的哈希碼,因此他們是同一個實例,但是s3、s4,是通過反射后用構造函數重新構造生成的實例,他們均與s1,s2不同。此時單例模式下產生了多個不同的對象,違反了設計原則。

基于上述反射可能造成的單例模式失效,考慮在私有的構造函數中添加是否初始化的標記位,使私有構造方法只可能被執行一次。

public class SingletonV6 { //是否已經初始化過的標記位 private static boolean isInitialized = false; //構造函數中,當實例已經被初始化時,不能繼續獲取新實例 private SingletonV6() { synchronized(SingletonV6.class) { if(isInitialized == false) { isInitialized = !isInitialized; }else { throw new RuntimeException('單例模式被破壞...'); } } } static class SingetonGet { private static final SingletonV6 instance = new SingletonV6(); } public static SingletonV6 getInstance() { return SingetonGet.instance; }}

測試代碼如下:

@Test public void test5() { SingletonV6 s1 = SingletonV6.getInstance(); SingletonV6 s2 = null; try { Class<SingletonV6> clazz = SingletonV6.class; Constructor<SingletonV6> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); s2 = constructor.newInstance(); }catch(Exception e) { e.printStackTrace(); } System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); }

運行上述代碼時,會拋出異常:

java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at SingletonTest.SingletonTest.test5(SingletonTest.java:98) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)Caused by: java.lang.RuntimeException: 單例模式被破壞... at SingletonTest.SingletonV6.<init>(SingletonV6.java:26) ... 28 more2052001577

7.序列化反序列化都不能破壞的單例模式

經過上述改進,反射也不能夠破壞單例模式了。但是,依然存在一種可能造成上述單例模式產生兩個不同的實例,那就是序列化。當一個對象A經過序列化,然后再反序列化,獲取到的對象B和A是否是同一個實例呢,驗證代碼如下:

/** * @Author {LearnAndGet} * @Time 2018年11月13日 * @Discription:測試序列化并反序列化是否還是同一對象 */package SingletonTest;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInput;import java.io.ObjectInputStream;import java.io.ObjectOutput;import java.io.ObjectOutputStream;public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub SingletonV6 s1 = SingletonV6.getInstance(); ObjectOutput objOut = null; try { //將s1序列化(記得將Singleton實現Serializable接口) objOut = new ObjectOutputStream(new FileOutputStream('c:a.objFile')); objOut.writeObject(s1); objOut.close(); //反序列化得到s2 ObjectInput objIn = new ObjectInputStream(new FileInputStream('c:a.objFile')); SingletonV6 s2 = (SingletonV6) objIn.readObject(); objIn.close(); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}

輸出結果如下:

1118140819990368553

可見,此時序列化前的對象s1和經過序列化->反序列化步驟后的到的對象s2,并不是同一個對象,因此,出現了兩個實例,再次違背了單例模式的設計原則。

為了消除問題,在單例模式類中,實現Serializable接口之后 添加對readResolve()方法的實現:當從I/O流中讀取對象時,readResolve()方法都會被調用到。實際上就是用readResolve()中返回的對象直接替換在反序列化過程中創建的對象,而被創建的對象則會被垃圾回收掉。這就確保了在序列化和反序列化的過程中沒人可以創建新的實例,修改后的代碼如下:

package SingletonTest;import java.io.Serializable;/** * @author LearnAndGet * * @time 2018年11月13日 * */public class SingletonV6 implements Serializable{ //是否已經初始化過的標記位 private static boolean isInitialized = false; //構造函數中,當實例已經被初始化時,不能繼續獲取新實例 private SingletonV6() { synchronized(SingletonV6.class) { if(isInitialized == false) { isInitialized = !isInitialized; }else { throw new RuntimeException('單例模式被破壞...'); } } } static class SingetonGet { private static final SingletonV6 instance = new SingletonV6(); } public static SingletonV6 getInstance() { return SingetonGet.instance; } //實現readResolve方法 private Object readResolve() { return getInstance(); }}

重新運行上述序列化和反序列過程,可以發現,此時得到的對象是同一對象。

11181408191118140819

8.總結

在實際開發中,根據自己的需要,選擇對應的單例模式即可,不一樣非要實現第7節中那種無堅不摧的單例模式。畢竟不是所有場景下都需要實現序列化接口, 也并不是所有人都會用反射來破壞單例模式。因此比較常用的是第5節中的,內部類單例模式,代碼簡潔明了,且節省空間。

以上就是java單例模式實現的方法的詳細內容,更多關于java單例模式的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
av高清不卡| 国产日产精品_国产精品毛片 | 国产成人精品三级高清久久91| 国产视频一区二| 国产欧美一区二区三区精品观看 | 国产日韩免费| 国产成人精品亚洲线观看| 欧美黄色网页| 伊人久久成人| 亚欧洲精品视频在线观看| 国产精品分类| 欧洲av一区二区| 亚洲欧美日本日韩| 91伊人久久| 久久久久久色| 久久精品国产久精国产| 日本欧美国产| 欧美精品羞羞答答| 日本不卡一区二区三区| 国产aa精品| 国产一级久久| 国产精选久久| 久久国产主播| 亚洲精品欧美| 精品国产精品国产偷麻豆| 国产一区亚洲| 日韩精品三级| 日韩在线短视频| 日本成人一区二区| se01亚洲视频 | 国产精品成久久久久| 99国产精品一区二区| 日韩在线观看一区二区| 久久国内精品视频| 欧洲一级精品| 中文字幕日本一区| 黑森林国产精品av| 午夜精品福利影院| 国产精品国产三级国产在线观看| 亚洲午夜在线| 久久xxx视频| 国产精品社区| 福利一区和二区| 亚州av日韩av| 欧美在线影院| 久久久久久夜| 国产探花在线精品一区二区| 欧美99久久| 你懂的国产精品永久在线| 宅男噜噜噜66国产日韩在线观看| 精品国产亚洲一区二区三区在线| 久久国产成人| 99精品国产一区二区三区| 国产亚洲精品美女久久 | 国产高清一区| 久久这里只有| 日韩一区二区三免费高清在线观看 | 国产欧美成人| 国产亚洲精品v| 日本一区二区高清不卡| 热久久久久久| 中文在线日韩| 伊人久久亚洲热| 日韩精品影视| 成人在线免费观看网站| 欧美一级网站| 久久高清国产| 精品在线播放| 日韩欧美二区| 精品91福利视频| 欧美永久精品| 美女91精品| 精品一区在线| 日韩av一级| a天堂资源在线| 久久亚洲道色| 国产精品久久久免费| 亚洲精品国模| 免费观看日韩电影| 激情综合自拍| 欧美大黑bbbbbbbbb在线| 成人啊v在线| 精精国产xxxx视频在线播放| 91亚洲国产高清| 麻豆一区二区在线| 国产欧美日韩免费观看| 亚洲精品韩国| 日韩在线视频一区二区三区| 免费一级片91| 亚洲精品乱码久久久久久蜜桃麻豆| 亚洲精品网址| 亚洲精品一区二区在线看| 欧美中文一区二区| 蜜臀av免费一区二区三区| 欧美成人午夜| 在线综合欧美| 综合欧美亚洲| 日韩中文一区二区| 国产日韩一区| 国产精品白丝久久av网站| 免费亚洲婷婷| 国产成人免费视频网站视频社区| 久久精品理论片| 精品一区二区三区中文字幕| 成午夜精品一区二区三区软件| zzzwww在线看片免费| 一区二区精品伦理...| 欧美一区久久久| 激情欧美日韩一区| 日韩专区欧美专区| 欧美一级二区| 日韩av在线中文字幕| 四虎884aa成人精品最新| 蜜桃国内精品久久久久软件9| 伊人久久成人| 日韩欧美高清一区二区三区| 日韩av资源网| 久久精品三级| 91精品蜜臀一区二区三区在线 | www.com.cn成人| 精品一区三区| 日本欧美一区| 国产一区二区三区四区二区| 亚洲精品一级二级| 蜜臀精品一区二区三区在线观看| 日韩av三区| 成人影视亚洲图片在线| 影视先锋久久| 青青草国产精品亚洲专区无| 免费在线观看一区| 婷婷激情一区| 亚洲三级网站| 精品日本视频| 欧美日韩高清| 国产日产精品_国产精品毛片| 日韩高清欧美| 最新国产精品视频| 国产一区2区在线观看| 中文亚洲免费| 久久精品系列| 亚洲免费中文| 久久免费视频66| 国产精品美女久久久| 国产精品久久久久77777丨| 久久精品一区二区不卡| 蜜桃免费网站一区二区三区| 欧美国产另类| 久久福利一区| 亚洲精品永久免费视频| 亚洲资源在线| 99视频精品全部免费在线视频| 综合色一区二区| 神马午夜久久| 麻豆91在线播放| 亚洲制服少妇| 精品国产亚洲日本| 亚洲一区有码| 三级精品视频| 国产精品日本一区二区三区在线| 欧美大黑bbbbbbbbb在线| 国产欧美精品| 天堂成人国产精品一区| 亚洲黄色免费看| 国产欧美69| 亚洲网址在线观看| 99久久久久久中文字幕一区| 国产高清亚洲| 热久久国产精品| 日韩精品欧美| 精品久久在线| 青草国产精品久久久久久| 国产一区导航| 欧美日韩一二三四| 国产成人久久| 国产精品qvod| 亚洲免费毛片| 国产日韩专区| 国户精品久久久久久久久久久不卡| 免费在线成人| 国产精选久久| 91亚洲精品视频在线观看| 麻豆亚洲精品| 国产手机视频一区二区| 亚洲福利免费| 久久精品亚洲人成影院| 国产盗摄——sm在线视频| 国产精品黄色| 日韩一区二区三免费高清在线观看 | 国产精品不卡| 国产精品羞羞答答在线观看| 亚洲三级精品| 免费久久99精品国产| 国产精品美女久久久浪潮软件| 欧美日韩视频免费观看| 精品国产麻豆| 久久精品国产成人一区二区三区| 国产精品视频一区视频二区| 亚洲69av| 天堂va欧美ⅴa亚洲va一国产| 精品一区欧美|