一篇文章讓你徹底搞懂單例設計模式
阿新 • • 發佈:2022-05-13
轉自:
http://www.java265.com/JavaCourse/202109/1153.html
下文是筆者編寫的單例模式實現的八種方式,如下所示:
單例模式的簡介
我們將一個類在當前程序中只有一個例項的這種模式,稱之為“單例模式”
那麼Java程式碼如何實現一個單例模式呢?下文將一一到來,如下所示:
單例模式的注意事項: 1.單例模式在一個程序中只有一個例項 2.單例類通常由自己建立自身的例項 3.單例類給其他物件提供的都是同一個例項
測試程式碼
package com.java265.Singleton; public class Test { public staticvoid main(String[] args) { // TODO Auto-generated method stub System.out.println("------單例模式-----"); //建立100個執行緒進行測試 for(int i=0;i<100;i++) { new Thread(()->{ System.out.println(Single01.getInstance()); }).start(); } } }
單例實現模式1
餓漢式單例模式:
直接使用一個靜態變數,在JVM載入類時,生成一個單例例項 如下
package com.java265.Singleton; public class Single01 { private static final Single01 INSTANCE = new Single01(); private Single01() {} public static Single01 getInstance () { return INSTANCE; } }
使用static靜態程式碼塊生成一個單例類
package com.java265.Singleton; public class Single02 { private static final Single02 INSTANCE; static { INSTANCE = new Single02(); } private Single02() {} public static Single02 getInstance() { return INSTANCE; } public void t() { System.out.println("Single02 t方法" + ""); } }
使用判斷的方式,建立單例模式,
但是此處不是一個執行緒安全的建立方式
package com.java265.Singleton; /* * 這是一個執行緒不安全的建立單例模式的方式 * 這是一個懶漢式的建立單例模式的方式 * */ public class Single03 { private static Single03 INSTANCE; private Single03() { } public static Single03 getInstance() { if(INSTANCE ==null) { // 多個執行緒都會被卡在此處, // 當sleep執行完畢後,多個執行緒會同時建立例項,此處的程式碼是產生執行緒不安全的根源 try { Thread.sleep(100); }catch(InterruptedException e) { } INSTANCE = new Single03(); } return INSTANCE; } }
使用 synchronized為方法加上鎖,使其執行緒安全
package com.java265.Singleton; public class Single04 { private static volatile Single04 INSTANCE; private Single04() { } /* * 懶漢式生成單例例項 此處使用 synchronized 安全鎖 */ public static synchronized Single04 getInstance() { if(INSTANCE ==null) { try { Thread.sleep(100); }catch(InterruptedException e) { } INSTANCE = new Single04(); } return INSTANCE; } }
減少鎖粒度,將synchronized關鍵字直接加在方法內部具體的位置上
package com.java265.Singleton; public class Single05 { private static Single05 INSTANCE; private Single05() { } public static Single05 getInstance() { if(INSTANCE ==null) { /* * 將鎖直接加到方法體裡面 此時出現了一個新的問題 當所有的執行緒都堵塞在此處,也會建立多個例項 */ synchronized(Single05.class) { try { Thread.sleep(100); }catch(InterruptedException e) { } INSTANCE = new Single05(); } } return INSTANCE; } }
將synchronized鎖放入在方法體中,同時使用雙重檢查,避免建立多個例項
package com.java265.Singleton; public class Single06 { private static Single06 INSTANCE; private Single06() { } public static Single06 getInstance() { if(INSTANCE ==null) { synchronized(Single06.class) { try { Thread.sleep(100); }catch(InterruptedException e) { } if(INSTANCE == null) { INSTANCE = new Single06(); } } } return INSTANCE; } }
使用靜態內部類的方式建立一個單例物件
此方式主要藉助JVM載入類時,內部類不會被載入
當我們使用內部類的時,才會被載入,此時由JVM保證靜態內部類的唯一性
package com.java265.Singleton; /* * 採用內部類的方式實現一個單例模式 * */ public class Single07 { private Single07() { } private static class Single07Holder { private final static Single07 INSTANCE = new Single07(); } public static Single07 getInstance() { return Single07Holder.INSTANCE; } }
使用列舉建立一個靜態內部類
package com.java265.Singleton; /* * 採用列舉實現一個單例模式 * */ public enum Single08 { INSTANCE; public static Single08 getInstance() { return INSTANCE; } }