美文网首页
单例模式

单例模式

作者: 云鲸鱼rain | 来源:发表于2019-03-07 13:40 被阅读0次

    又回到了这里,单例模式。
    毕业前一直如雷贯耳,也曾亲密接触,但是只得其表不得其里。
    终于毕业后在工作中用到了单例。那种感觉就是:“复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田美池桑竹之属。”


    正文:
    先说一下学习链接,菜鸟教程
    什么是单例?
    就是有这么一个类,它只能创建自己的对象,有且只有一个自己的对象。并向外部提供一个访问这个对象的方式。
    单例解决了什么麻烦?(为什么使用单例)
    1、如果一个类频繁的创建然后销毁,麻烦不麻烦?很麻烦,用单例,只创建一次,每次需要的时候直接调用就行。
    2、控制实例数目,节省系统资源。
    单例的特点是什么?(使用单例需要注意的地方)
    1、构造函数必须私有化。
    2、不能继承。
    3、需要同步锁synchronized。
    解释:
    1、为什么构造函数必须私有化?如果不私有化,那默认是public,那就可以无限使用Singleton singleton = new Singleton();那就会不断实例化单例类。违反了单例的设计模式,提供不了单例所带来的优势。
    2、为什么不能继承?因为构造函数私有化了。如果继承,子类的构造函数默认super();父类私有化的构造函数怎么super();?
    3、为什么需要同步锁synchronized?防止多线程进入造成单例类被多次实例化。

    单例代码怎么实现?
    (线程安全是指:避免多个线程同时使用一个对象;不安全反之。)
    (Lazy初始化是指:使用到的时候才进行初始化;反之就是在类加载的时候就初始化:即时加载)

    1、懒汉式,线程不安全,Lazy初始化
    不支持多线程,因为没有加锁,synchronized。

    package test;
    
    public class Singleton {
        
        private Singleton(){}
        
        private static Singleton instance;
        
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    2、懒汉式,线程安全,Lazy初始化
    支持多线程,加锁synchronized,但是效率低。

    package test;
    
    public class Singleton {
        
        private Singleton(){}
        
        private static Singleton instance;
            
        public synchronized static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    3、饿汉式,线程安全,即时加载
    没有加锁,执行效率高,类加载就初始化,浪费内存,容易产生垃圾。
    即时加载容易理解,类初始化的时候,就要new Singleton();那既然没有synchronized,为什么还会线程安全?
    因为classloader机制避免了多线程的同步问题。那什么是classloader机制?为什么避免了多线程?查了一些类加载的资料,还不是很懂,目前的理解是:多个线程同时实例化对象的时候,如果不存在Singleton对象,则触发类的初始化,如果存在Singleton对象,则直接调用。(类加载的文章链接点击这里

    package test;
    
    public class Singleton {
        
        private Singleton(){}
        
        private static Singleton instance = new Singleton();
            
        public synchronized static Singleton getInstance() {
            return instance;
        }
    }
    

    4、双检锁/双重校验锁(DCL,即 double-checked locking)
    线程安全,懒加载,并且高性能。
    其实这种单例我是没懂,单写出来记录一下。疑问点有两点。一是volatile关键字,看了例子,大概是不具备原子性,具备可见性。比synchronized更轻量级的同步机制,单原理和使用场景还没搞明白。二是双城instance == null 的目的。

    package test;
    
    public class Singleton {
        
        private Singleton(){}
        
        private volatile static Singleton instance;
            
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    

    5、登记式/静态内部类//(此单例模式代码摘抄自菜鸟教程,因为这个好多地方我还没看懂)
    这种单例模式是在饿汉式单例的升级版,为什么?因为在饿汉式的基础上达到lazy loading的效果。还能达到双检锁单例的功效。

    public class Singleton {  
        private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
        }  
    }
    

    6、枚举式
    线程安全,非懒加载。(介绍枚举式单例详细的一篇博客
    实现单例最佳的方式,自动支持序列化机制,防止被多次实例化。
    线程安全的原因:枚举类在被虚拟机加载的时候会保证线程安全的被初始化。
    在序列化方面:枚举的序列化和反序列化是有特殊定制的。这就可以避免反序列化过程中由于反射而导致的单例被破坏问题。
    线程安全自然不用多说,那么序列化和反序列化是什么呢?先把问题放在这儿。

    package test;
    
    public enum Singleton {
        instance;//public static final Singleton  instance;
    }
    

    相关文章

      网友评论

          本文标题:单例模式

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