美文网首页java
设计模式--单例模式

设计模式--单例模式

作者: 是哪的鸭 | 来源:发表于2020-02-19 19:11 被阅读0次

    单例模式

    一个类只能有一个对象。该类自己负责创建对象,同时确保只有一个对象被创建。

    1. 单例类只能有一个实例
    2. 单例类必须自己创建自己的唯一实例
    3. 单例类必须给其他所有类提供这一实例

    使用场景:

    • 要求产生唯一的序列号
    • WEB中的技术去,不用每次刷新都在书库里加一次。用单例先缓起来
    • 创建的一个对象需要消耗的资源过多,比如I/O与数据库的连接等。

    实现方法

    1.懒汉式

    Lazy初始化:
    线程安全:
    描述: 最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
    这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

    具体实现

    //懒汉式线程安全做法为加锁,在getInstance方法上加sychronized锁。但是这样会影响效率
    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
      
        public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
        }  
         //doSomething() 该实例支持的行为
    }
    

    2.饿汉式

    Lazy初始化:
    线程安全:
    描述: 常用方法,但是容易产生垃圾对象。基于classloader机制避免了多线程的同步问题。在类加载时就实例化对象,没达到lazy loading效果

    • 优点:没有加锁,效率高
    • 缺点:类加载时就初始化,可能会产生垃圾

    具体实现

    public class Singleton{
        private static Singleton instance=new Singleton();
        private Singleton(){};
        public static Singleton getInstance(){
            return instance;
        }
         //doSomething() 该实例支持的行为
    }
    

    3.双检锁/双重校验锁(DCL)

    JDK版本: 1.5起
    Lazy初始化:
    多线程安全:
    描述: 采用双锁机制,安全且在多线程情况下能保持高性能。getInstance()的性能对程序很关键。

    具体实现

    public class Singleton{
        //当singleton不为null时通知想要实例化的其他线程  
        private volatile static Singleton singleton;
        private Singleton(){};
        public Singleton getInstance(){
            //判断是否为空,为空则获得sychronized锁
            if(instance==null){
                sychronized(Singleton.class);
                //获得sychronized锁后再次判断,防止获得锁时,已经被实例化。
                if(singleton==null){
                    singleton=new Singleton();
                }
            }
            return singleton;
        }
        
         //doSomething() 该实例支持的行为
    }
    

    登记式/静态内部类

    Lazy初始化:
    线程安全:
    描述: 能达到双检锁一样的功效。但是实现更简单。本方法采用classloader机制来确保初始化时只有一个线程。同饿汉式不同,饿汉式只要类被加载了,instance一定被实例化。本方法只有通过主动调用getInstance()来显示装在SingletonHolder,从而实例化instance

    具体实现

        public class Singleton{
            private static class SingletonHolder{
                private static final Singleton INSTANCE =new Singleton();
            }
            private Singleton(){};
            public static final Singleton getInstance(){
                return SingletonHolder.INSTANCE;
            }
            
             //doSomething() 该实例支持的行为
        }
    

    6.枚举

    JDK版本: 1.5起
    是否Lazy初始化:
    多线程安全:
    描述: 实现单例模式的最佳方法。简洁,而且支持序列化机制,绝对防止多次被实例化。代码可读性差

    具体实现

        public enum Singleton{
            INSTANCE
            
            //doSomething() 该实例支持的行为
            
            //可以省略此方法,通过Single.INSTANCE进行操作
            public static Singleton getInstance(){
                return Singleton.INSTANCE
            }
            
        }
    

    总结

    枚举式不常用,可读性差。
    既要求线程安全,又要求Lazy加载使用双检锁式。
    要求线程安全,不要求Lazy加载使用饿汉式。

    注意: 前五种方法可能会多次实例化,当实例被写入到文件到反序列化成实例时,会重复实例化。为了避免这种情况。如果涉及到序列化、反序列化时,我们需要重写readResolve方法,以让实例唯一。

    private Object readResolve() throws ObjectStreamException{
        return singleton;
    }
    

    相关文章

      网友评论

        本文标题:设计模式--单例模式

        本文链接:https://www.haomeiwen.com/subject/okczfhtx.html