zoukankan      html  css  js  c++  java
  • 单例模式 之 单例模式——懒汉模式

    懒汉模式:和饿汉模式不同,懒汉模式并不会一开始声明对象,而是需要等到调用时再声明对象。他很懒,所以你叫“它”它才会动...

    代码1:

    /**
     * 懒汉模式
     */
    public class LazybonesSingleton1 {
        //先声明
        private static LazybonesSingleton instance;
        /**
         * 禁止外部构建
         */
        private LazybonesSingleton(){}
    
        /**
         * 对外提供调用方法
         * @return
         */
        public static LazybonesSingleton getInstance() {
            if(instance==null){
                instance=new LazybonesSingleton();
            }
    
            return instance;
        }
    
        /**
         * 测试
         * @param args
         */
        public static void main(String[] args) {
            for(int i=0;i<20;i++){
                new Thread(()->{
                    System.out.println(LazybonesSingleton.getInstance());
                }).start();
            }
        }
    
    
    }

    代码1 测试结果:发现 第一个线程运行时 和剩下线程运行 ,并不是一个单例。

    这是因为多线程时,很有可能出现两个或多个线程同时执行。

    也就是说他们同时运行到了 if(instance==null) 所以都创建了一个对象的实例

    com.company.LazybonesSingleton@55477623
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    
    Process finished with exit code 0

    代码2:根据上述问题,我们进行了优化  getInstance 使用了 synchronized

    /**
     * 懒汉模式
     */
    public class LazybonesSingleton2 {
        //先声明
        private static LazybonesSingleton instance;
        /**
         * 禁止外部构建
         */
        private LazybonesSingleton(){}
    
        /**
         * 对外提供调用方法
         * @return
         */
        public static synchronized LazybonesSingleton getInstance() {
            if(instance==null){
                instance=new LazybonesSingleton();
            }
    
            return instance;
        }
    
        /**
         * 测试
         * @param args
         */
        public static void main(String[] args) {
            for(int i=0;i<20;i++){
                new Thread(()->{
                    System.out.println(LazybonesSingleton.getInstance());
                }).start();
            }
        }
    
    
    }

    代码2 测试结果:运行结果为同一个用例,保证了安全性。

    但是这里出现了一个问题 synchronized 会让 线程变成串行执行synchronized后,其他线程会在外进行等待,直到运行结束。再有下一个线程运行,剩下未执行的线程继续等待,同样直到该线程运行结束 )。

    虽然保证了安全性,但是性能却很差。

    com.company.LazybonesSingleton@3996d457。
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    com.company.LazybonesSingleton@3996d457
    
    Process finished with exit code 0

    代码3:我们再进行优化,将 synchronized  放到 if(instance==null) 里面

    这样其他线程就不用在执行 getInstance() 时进行等待了,性能也有所改进。

    /**
     * 懒汉模式
     */
    public class LazybonesSingleton3 {
        //先声明
        private static LazybonesSingleton instance;
        /**
         * 禁止外部构建
         */
        private LazybonesSingleton(){}
    
        /**
         * 对外提供调用方法
         * @return
         */
        public static  LazybonesSingleton getInstance() {
            if(instance==null){
                synchronized (LazybonesSingleton.class){
                    instance=new LazybonesSingleton();
                }
            }
    
            return instance;
        }
    
        /**
         * 测试
         * @param args
         */
        public static void main(String[] args) {
            for(int i=0;i<20;i++){
                new Thread(()->{
                    System.out.println(LazybonesSingleton.getInstance());
                }).start();
            }
        }
    
    
    }

    代码3 测试结果:虽然性能有所改进,但是依然存在安全问题,

    原因在于:多线程运行过程中很有可能同时运行到 if(instance==null),虽然会在外面等待由另一个线程执行完再执行,所以也会存在创建多个实例的问题

    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    
    Process finished with exit code 0

    -----------------------------以下是我运行多次的结果-----------------------------------

    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@55477623
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707
    com.company.LazybonesSingleton@4f0c4707

    Process finished with exit code 0




    代码4:在 synchronized 中 再判断一次是否为空,这样便能解决 代码3产生的问题。

    此种方式 可以叫 双重检测(DCL),便能解决 懒加载的安全问题

    /**
     * 懒汉模式
     */
    public class LazybonesSingleton {
        //先声明
        private static LazybonesSingleton instance;
        /**
         * 禁止外部构建
         */
        private LazybonesSingleton(){}
    
        /**
         * 对外提供调用方法
         * @return
         */
        public static  LazybonesSingleton getInstance() {
            if(instance==null){
                synchronized (LazybonesSingleton.class){
                    if(instance==null){
                        instance=new LazybonesSingleton();
                    }
                }
            }
    
            return instance;
        }
    
        /**
         * 测试
         * @param args
         */
        public static void main(String[] args) {
            for(int i=0;i<20;i++){
                new Thread(()->{
                    System.out.println(LazybonesSingleton.getInstance());
                }).start();
            }
        }
    
    
    }

    代码4 运行结果:

    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    com.company.LazybonesSingleton@19281561
    
    Process finished with exit code 0
  • 相关阅读:
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    冒泡排序和选择排序
  • 原文地址:https://www.cnblogs.com/zhangzhonghui/p/11460731.html
Copyright © 2011-2022 走看看