亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中的單例模式實例分析

發布時間:2022-02-23 09:12:58 來源:億速云 閱讀:123 作者:iii 欄目:開發技術

本篇內容介紹了“Java中的單例模式實例分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    1、定義

    單例模式(Singleton Pattern)是指確保一個類在任何情況下都絕對只有一個實例,并提供一個全局訪問點。
    隱藏其所有的構造方法。
    屬于創建型模式。

    2、適用場景

    確保任何情況下都絕對只有一個實例。

    3、常見寫法

    第一種:餓漢式單例:在單例類首次加載時就創建實例

    /**
     * @Package: com.hzg.study.design.pattern.singleton.hungry
     * @Description: 餓漢式單例
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-18 16:15
     */
    public class HungrySingleton {
        private static final HungrySingleton INSTANCE = new HungrySingleton();
        /**
         * 私有化構造器
         */
        private HungrySingleton() {
        }
        /**
         * 全局訪問點
         */
        public static HungrySingleton getInstance() {
            return INSTANCE;
        }
    }

    餓漢式單例靜態代碼塊寫法:

    /**
     * @Package: com.hzg.study.design.pattern.singleton.hungry
     * @Description: 餓漢式單例(靜態代碼塊初始化)
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-18 16:15
     */
    public class HungryStaticSingleton {
        private static final HungryStaticSingleton INSTANCE;
        /**
         * 靜態代碼塊
         */
        static {
            INSTANCE = new HungryStaticSingleton();
        }
        /**
         * 私有化構造器
         */
        private HungryStaticSingleton() {
        }
        /**
         * 全局訪問點
         */
        public static HungryStaticSingleton getInstance() {
            return INSTANCE;
        }
    }

    第二種:懶漢式單例:被外部類調用時才創建實例

    /**
     * @Package: com.hzg.study.design.pattern.singleton.lazy
     * @Description: 懶漢式單例
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-18 16:24
     */
    public class LazySingleton {
        private static LazySingleton INSTANCE = null;
        /**
         * 私有化構造器
         */
        private LazySingleton() {
        }
        /**
         * 全局訪問點
         */
        public static LazySingleton getInstance() {
            if (INSTANCE == null) {
                INSTANCE = new LazySingleton();
            }
            return INSTANCE;
        }
    }

    懶漢式單例靜態匿名內部類寫法(性能最優):

    /**
     * @Package: com.hzg.study.design.pattern.singleton.lazy
     * @Description: 懶漢式單例(匿名靜態內部類)(性能最優)
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-18 18:00
     */
    public class LazyInnerClazzSingleton implements Serializable {
        /**
         * 私有化構造器
         */
        private LazyInnerClazzSingleton() {
        }
        /**
         * 全局訪問點
         */
        public static final LazyInnerClazzSingleton getInstance() {
            return LazyHolder.INSTANCE;
        }
        private static class LazyHolder {
            private static final LazyInnerClazzSingleton INSTANCE = new LazyInnerClazzSingleton();
        }
    }

    第三種:注冊式單例:將每一個實例都緩存到統一的容器中,使用唯一標識獲取實例

    注冊式單例枚舉寫法:

    /**
     * @Package: com.hzg.study.design.pattern.singleton.registry
     * @Description: 注冊式單例-枚舉單例
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-21 10:24
     */
    public enum EnumSingleton {
        INSTANCE;
        /**
         * 如果需要讓其他對象成為單例,只需要將data改為目標類對象即可
         * <p/>
         * 通過getter和setter操作
         */
        private Object data;
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
        public static EnumSingleton getInstance() {
            return INSTANCE;
        }
    }

    Spring中常見的注冊式單例寫法:

    /**
     * @Package: com.hzg.study.design.pattern.singleton.registry
     * @Description: Spring中常見的注冊式單例寫法
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-21 10:54
     */
    public class ContainerSingleton {
        /**
         * spring ioc
         */
        private static Map<String, Object> container = new ConcurrentHashMap<>();
        private ContainerSingleton() {
        }
        public static Object getBean(String clazzName) {
            // 加synchronized代碼塊保證線程安全
            synchronized (container) {
                if (!container.containsKey(clazzName)) {
                    Object object = null;
                    try {
                        object = Class.forName(clazzName).newInstance();
                        container.put(clazzName, object);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return object;
                }
                return container.get(clazzName);
            }
        }
    }

    第四種:ThreadLocal線程單例:保證線程內部的全局唯一,且天生線程安全

    /**
     * @Package: com.hzg.study.design.pattern.singleton.threadlocal
     * @Description: ThreadLocal線程單例(偽安全)
     * @Description: 可以使用ThreadLocal動態切換數據源
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-21 11:10
     */
    public class ThreadLocalSingleton {
        public static final ThreadLocal<ThreadLocalSingleton> THREAD_LOCAL = new ThreadLocal<ThreadLocalSingleton>() {
            @Override
            protected ThreadLocalSingleton initialValue() {
                return new ThreadLocalSingleton();
            }
        };
        private ThreadLocalSingleton() {
        }
        public static ThreadLocalSingleton getInstance() {
            return THREAD_LOCAL.get();
        }
    }

    4、如何防止單例被破壞

    1.多線程破壞單例以及解決方法

    以懶漢式單例LazySingleton為例:

    首先寫一個線程實現類,如下:

    import com.hzg.study.design.pattern.singleton.lazy.LazySingleton;
    /**
     * @Package: com.hzg.study.design.pattern.singleton.lazy.test
     * @Description:
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-18 16:32
     */
    public class ExecutorThread implements Runnable {
        @Override
        public void run() {
            LazySingleton instance = LazySingleton.getInstance();
            System.out.println(Thread.currentThread().getName() + ":" + instance);
        }
    }

    main方法測試:

    public class LazySingletonTest {
        public static void main(String[] args) {
            Thread thread1 = new Thread(new ExecutorThread());
            thread1.start();
            Thread thread2 = new Thread(new ExecutorThread());
            thread2.start();
            System.out.println("----------------------------------------");
        }
    }

    測試結果:顯然出現了兩個不同的實例

    Java中的單例模式實例分析

    解決方法1:加synchronized關鍵字修飾getInstance方法

    public class LazySingleton {
        private static LazySingleton INSTANCE = null;
        /**
         * 私有化構造器
         */
        private LazySingleton() {
        }
        /**
         * 全局訪問點
         * <p/>
         * synchronized關鍵字修飾方法
         */
        public static synchronized LazySingleton getInstance() {
            if (INSTANCE == null) {
                INSTANCE = new LazySingleton();
            }
            return INSTANCE;
        }
    }

    解決方法2:雙重檢查鎖DoubleCheck

    /**
     * @Package: com.hzg.study.design.pattern.singleton.lazy
     * @Description: 懶漢式單例(雙重檢查鎖)
     * @Author: HuangZhiGao
     * @CreateDate: 2022-02-18 17:08
     */
    public class LazyDoubleCheckSingleton {
        /**
         * volatile關鍵字修飾,避免指令重排序引發問題
         */
        private volatile static LazyDoubleCheckSingleton INSTANCE = null;
        /**
         * 私有化構造器
         */
        private LazyDoubleCheckSingleton() {
        }
        /**
         * 全局訪問點
         * <p/>
         * 雙重檢查鎖
         */
        public static LazyDoubleCheckSingleton getInstance() {
            if (INSTANCE == null) {
                synchronized (LazyDoubleCheckSingleton.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new LazyDoubleCheckSingleton();
                    }
                }
            }
            return INSTANCE;
        }
    }

    2.反射破壞單例以及解決方法

    以懶漢式單例靜態匿名內部類寫法LazyInnerClazzSingleton為例:

    main方法測試:

    public class LazyInnerClazzSingletonTest {
        public static void main(String[] args) {
            try {
                Class<LazyInnerClazzSingleton> aClazz = LazyInnerClazzSingleton.class;
                Constructor<LazyInnerClazzSingleton> declaredConstructor = aClazz.getDeclaredConstructor(null);
                declaredConstructor.setAccessible(true);
                LazyInnerClazzSingleton instance1 = declaredConstructor.newInstance();
                LazyInnerClazzSingleton instance2 = LazyInnerClazzSingleton.getInstance();
                System.out.println(instance1);
                System.out.println(instance2);
                System.out.println(instance1 == instance2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    測試結果:構建了兩個不同的實例

    Java中的單例模式實例分析

    解決方法:在構造器中增加如下if判斷

    public class LazyInnerClazzSingleton implements Serializable {
        /**
         * 私有化構造器
         */
        private LazyInnerClazzSingleton() {
            if (null != LazyHolder.INSTANCE) {
                throw new RuntimeException("不允許構建多個實例");
            }
        }
        /**
         * 全局訪問點
         */
        public static final LazyInnerClazzSingleton getInstance() {
            return LazyHolder.INSTANCE;
        }
        private static class LazyHolder {
            private static final LazyInnerClazzSingleton INSTANCE = new LazyInnerClazzSingleton();
        }
    }

    再次測試:

    Java中的單例模式實例分析

    3.序列化破壞單例以及解決方法

    以懶漢式單例靜態匿名內部類寫法LazyInnerClazzSingleton為例:注意必須先實現序列化接口Serializable

    main方法測試:

        public static void main(String[] args) {
            LazyInnerClazzSingleton instance1 = LazyInnerClazzSingleton.getInstance();
            LazyInnerClazzSingleton instance2 = null;
            try (
                    FileOutputStream fileOutputStream = new FileOutputStream("LazyInnerClazzSingleton.obj");
                    ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
                    FileInputStream fileInputStream = new FileInputStream("LazyInnerClazzSingleton.obj");
                    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            ) {
                // 序列化
                objectOutputStream.writeObject(instance1);
                objectOutputStream.flush();
                // 反序列化
                instance2 = (LazyInnerClazzSingleton) objectInputStream.readObject();
                System.out.println(instance1);
                System.out.println(instance2);
                System.out.println(instance1 == instance2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    測試結果:構建了兩個不同的實例

    Java中的單例模式實例分析

    解決方法:新增readResolve方法

    public class LazyInnerClazzSingleton implements Serializable {
        /**
         * 私有化構造器
         */
        private LazyInnerClazzSingleton() {
            if (null != LazyHolder.INSTANCE) {
                throw new RuntimeException("不允許構建多個實例");
            }
        }
        /**
         * 全局訪問點
         */
        public static final LazyInnerClazzSingleton getInstance() {
            return LazyHolder.INSTANCE;
        }
        private static class LazyHolder {
            private static final LazyInnerClazzSingleton INSTANCE = new LazyInnerClazzSingleton();
        }
        /**
         * 重寫readResolve方法,實際還是創建了兩次,只不過是覆蓋了反序列化出來的對象,之前反序列化出來的對象會被GC回收
         * 發生在JVM層面,相對來說比較安全
         */
        private Object readResolve() {
            return LazyHolder.INSTANCE;
        }
    }

    5、優缺點

    優點:

    在內存中只有一個實例,減少了內存開銷。
    可以避免對資源的多重占用。
    設置全局訪問點,嚴格控制訪問。

    缺點:

    沒有接口,擴展困難。
    如果要擴展單例對象,只有修改代碼,沒有其他途徑。
    不符合開閉原則

    “Java中的單例模式實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    长乐市| 东山县| 通道| 广饶县| 西昌市| 绥江县| 富蕴县| 海阳市| 临沧市| 隆昌县| 凤凰县| 利辛县| 通河县| 金昌市| 黄龙县| 恩平市| 白山市| 黔南| 封丘县| 武安市| 盈江县| 澜沧| 郯城县| 乃东县| 四子王旗| 钟山县| 安新县| 宜春市| 廉江市| 沾益县| 开远市| 元朗区| 诸城市| 桦南县| 鹿泉市| 三明市| 南阳市| 吉安市| 伊金霍洛旗| 鄱阳县| 金湖县|