zoukankan      html  css  js  c++  java
  • 设计模式之单例模式 Singleton实现

    饿汉式

    •           饿汉式单例模式,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题,

                         因此可以省略synchronized关键字

    •           问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费

             

    public class SingletonDemo1 {
        //类初始化时,立即加载这个对象(没有延时加载的优势),,记载类时,天然的是线程安全的
        private static SingletonDemo1 instance = new SingletonDemo1(); 
        private SingletonDemo1(){
            
        };
        
        //方法没有同步,效率高
        public static SingletonDemo1 getInstance(){
            return instance;
        }
        
    }

    懒汉式

    • Lazy Load,延时加载,真正用到的时候再加载
    • 每次都得使用同步,synchronized,效率就底下了。
    public class SingletonDemo2 {
        //类初始化时,不初始化这个对象,(延时加载,真正用到的时候再创建)
        private static SingletonDemo2 instance ; 
        private SingletonDemo2(){
            
        };
        
        //方法同步,效率低
        public static synchronized SingletonDemo2 getInstance(){
            
            
            if(instance==null){
                instance= new SingletonDemo2();
            }
            return instance;
        }
        
    }

    双重检测锁

    • 双重检测判断
    • 使用volatile关键字,保证可见性
    public class Singleton {
        private volatile static Singleton sSingleton;
    
        private Singleton() {
        }
    
        public static Singleton getSingleton() {
            if (sSingleton == null) {
                synchronized (Singleton.class) {
                    if (sSingleton == null) {
                        sSingleton = new Singleton();
                    }
                }
            }
            return sSingleton;
        }
    }

     静态内部类

    • 外部类没有static关键字,所以不会立即加载
    • 只有调用getInstance()时才会加载静态内部类,线程安全。instance前面加了static final关键字,因此保证了内存中只有这样一个实例存在,且只能赋值一次,final保证线程安全
    • 具有并发高效调用和延迟加载的双重优点
    public class SingletonDemo3 {
        
        private static class SingletonClassInstance{
            private static final SingletonDemo3 instance = new SingletonDemo3() ; 
        }
        
        private SingletonDemo3(){
            
        }
        
        public static SingletonDemo3 getInstance(){
            return SingletonClassInstance.instance;
        }
        
    }

    枚举实现

    • 实现简单
    • 枚举本身就是单例模式
    public enum SingletonDemo4 {
        
        //枚举元素本身就是单例对象
        INSTANCE;
        
        //添加自己需要的操作
        public void singletonOperation(){
            
        }
    }

    如何防止反射和反序列化漏洞

    • 反射可以破解上面几种(不包含枚举式)实现方式  --------------------------可以在构造方法中手动抛出异常控制
    • 反序列化可以破解上面几种(不包含枚举式)实现方式

                -------可以通过定义readResolve()防止获得不同对象。
                --------反序列化时,如果对象所在类定义了readResolve(),定义返回哪个对象,实际是一种回调。

    public class SingletonDemo5 {
        //类初始化时,不初始化这个对象,(延时加载,真正用到的时候再创建)
            private static SingletonDemo5 instance ; 
            private SingletonDemo5(){
                if(instance !=null){
                    throw new RuntimeException();
                }
            }
            
            //方法同步,效率低
            public static synchronized SingletonDemo5 getInstance(){
                if(instance==null){
                    instance= new SingletonDemo5();
                }
                return instance;
            }
            
            //反序列化时,如果定义了readResolve(),则直接返回此方法指定的对象,而不需要单独创建新的对象
            private Object readResolve(){
                return instance;
            }
    }

    五种单例模式比较

    单例对象占用资源少,不需要延时加载   -------枚举类好于饿汉式

    单例对象占用资源大,需要延时加载      -------静态内部类好于懒汉式

  • 相关阅读:
    学习总结javascript和ajax,php,和css
    css基础二
    JQUERY基础
    JS基础与DOM操作(一)
    div布局
    样式表
    框架及其他小技巧
    表格与表单
    HTML基础
    二阶段测试
  • 原文地址:https://www.cnblogs.com/qingdaofu/p/7465910.html
Copyright © 2011-2022 走看看