當前位置:網站首頁>單例模式(你真的了解單例模式麼?)

單例模式(你真的了解單例模式麼?)

2022-01-28 02:16:06 程序員社區

單例模式(你真的了解單例模式麼?) , 你了解嗎? 本文就為大家帶來了一篇 單例模式(你真的了解單例模式麼?) 一起看看吧!
另外小編還收集了很多不錯的編程資源,希望對你有幫助:點擊查看
祝您生活愉快~

你真的了解單例模式麼?
廢話不多說,直接上幹貨

餓漢式

/** * 餓漢式 * 類加載到內存後,就實例化一個單例,JVM保證線程安全 * 簡單實用,推薦使用! * 唯一缺點:不管用到與否,類裝載時就完成實例化 * (話說你不用的,你裝載它幹啥) */public class Mgr01 {    private static final Mgr01 INSTANCE = new Mgr01();    private Mgr01() {}    public static Mgr01 getInstance() {        return INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        Mgr01 m1 = Mgr01.getInstance();        Mgr01 m2 = Mgr01.getInstance();        System.out.println(m1 == m2);    }}/** * 跟Mgr01是一個意思 */public class Mgr02 {    private static final Mgr02 INSTANCE;    static {        INSTANCE = new Mgr02();    }    private Mgr02() {}    public static Mgr02 getInstance() {        return INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        Mgr02 m1 = Mgr02.getInstance();        Mgr02 m2 = Mgr02.getInstance();        System.out.println(m1 == m2);    }}

懶漢式

/** * lazy loading * 也稱懶漢式 * 雖然達到了按需初始化的目的,但卻帶來線程不安全的問題 * 達不到單利的目的 */public class Mgr03 {    private static Mgr03 INSTANCE;    private Mgr03() {}    public static Mgr03 getInstance() {        if (INSTANCE == null) {            try {                Thread.sleep(1);            } catch (InterruptedException e) {                e.printStackTrace();            }            INSTANCE = new Mgr03();        }        return INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        for (int i = 0; i < 100; i++) {            new Thread(() ->                    System.out.println(Mgr03.getInstance().hashCode())            ).start();        }    }}/** * lazy loading * 也稱懶漢式 * 雖然達到了按需初始化的目的,但卻帶來線程不安全的問題 * 可以通過synchronized解决,但也帶來效率下降 * 注意:synchronized 不能禁止指令重排序 */public class Mgr04 {    private static Mgr04 INSTANCE;    private Mgr04() {}    public static synchronized Mgr04 getInstance() {        if (INSTANCE == null) {            try {                Thread.sleep(1);            } catch (InterruptedException e) {                e.printStackTrace();            }            INSTANCE = new Mgr04();        }        return INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        for (int i = 0; i < 100; i++) {            new Thread(() -> {                System.out.println(Mgr04.getInstance().hashCode());            }).start();        }    }}/** * lazy loading * 也稱懶漢式 * 雖然達到了按需初始化的目的,但卻帶來線程不安全的問題 * 可以通過synchronized解决,但也帶來效率下降 * 同Mgr03一樣達不到單利目的 */public class Mgr05 {    private static Mgr05 INSTANCE;    private Mgr05() {}    public static Mgr05 getInstance() {        if (INSTANCE == null) {            //妄圖通過减小同步代碼塊的方式提高效率,然後不可行            synchronized (Mgr05.class) {                try {                    Thread.sleep(1);                } catch (InterruptedException e) {                    e.printStackTrace();                }                INSTANCE = new Mgr05();            }        }        return INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        for (int i = 0; i < 100; i++) {            new Thread(() -> {                System.out.println(Mgr05.getInstance().hashCode());            }).start();        }    }}/** * lazy loading * 也稱懶漢式 * 雖然達到了按需初始化的目的,但卻帶來線程不安全的問題 * 可以通過synchronized解决,但也帶來效率下降 * 注意:volatile - 是禁止指令重排序的(從INSTANCE = new Mgr06() 分為3部 說起)。 */public class Mgr06 {    private static volatile Mgr06 INSTANCE; //JIT    private Mgr06() {}    public static Mgr06 getInstance() {        if (INSTANCE == null) {            // 雙重檢查            synchronized (Mgr06.class) {                if (INSTANCE == null) {                    try {                        Thread.sleep(1);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    INSTANCE = new Mgr06();                }            }        }        return INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        for (int i = 0; i < 100; i++) {            new Thread(() -> {                System.out.println(Mgr06.getInstance().hashCode());            }).start();        }    }}

對象創建過程-指令重排:https://www.jianshu.com/p/97d20f8c5305

靜態內部類方式

/** * 靜態內部類方式 * JVM保證單例 * 加載外部類時不會加載內部類,這樣可以實現懶加載 */public class Mgr07 {    private Mgr07() {    }    private static class Mgr07Holder {        private final static Mgr07 INSTANCE = new Mgr07();    }    public static Mgr07 getInstance() {        return Mgr07Holder.INSTANCE;    }    public void m() {        System.out.println("m");    }    public static void main(String[] args) {        for (int i = 0; i < 100; i++) {            new Thread(() -> {                System.out.println(Mgr07.getInstance().hashCode());            }).start();        }    }}

枚舉

/** * 不僅可以解决線程同步,還可以防止反序列化 * 線程安全,調用效率高,不能延時加載,可以天然的防止反射和反序列化調用 */public enum Mgr08 {    INSTANCE;    public void m() {}    public static void main(String[] args) {        for (int i = 0; i < 100; i++) {            new Thread(() -> {                System.out.println(Mgr08.INSTANCE.hashCode());            }).start();        }    }}
  • 各比特看官,以上8種單利模式你們都見過麼,你還敢說你們懂單例模式麼?
  • 其實單例模式不是一個簡單的設計模式。
  • 推薦使用Mgr01,因為簡單
  • Mgr06、Mgr07 和 Mgr08比較完美

————————————————————
坐標帝都,白天上班族,晚上是知識的分享者
如果讀完覺得有收獲的話,歡迎點贊加關注

版權聲明
本文為[程序員社區]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/01/202201280216059769.html

隨機推薦