zoukankan      html  css  js  c++  java
  • 创建型之单例模式

    前言

      单例模式随处可见,用处也很大,但是写好一个单例模式很不容易,拔出萝卜带出泥,面试也经常会被问到,今天就来总结一下。

      什么是单例?

    1. 单例类只能有1个实例对象,
    2. 单例类必须自己创建该实例,别人不能创建
    3. 单例类必须该所有其他对象提供该实例

    1. 饥饿式

    /**
     * 1-饿汉式单例类
     */
    public class EagerSingleton {
    
        //private保证实例不被直接访问,static保证只有1份,final保证这1份不被修改
        private static final EagerSingleton instance = new EagerSingleton();
    
        //private保证不被其它类new出来
        private EagerSingleton(){}
    
        //静态工厂方法,给其它对象提供相同方法
        public static EagerSingleton getInstance(){
            return instance;
        }
    }
    

      优点:在类被加载的时候,就创建了实例,多线程下是安全的。
      缺点:创建单例的时机过于急躁,在没有用到单例之前,占用了内存,而且初始化加载的配置到最后可能并不是我们想要的

    2. 懒汉式

    /**
     * 2-懒汉式单例模式
     */
    public class LazySingleton {
    
        //当getInstance方法被调用时才会被创建,没有final修饰,不能保证线程安全
        private static LazySingleton instance = null;
    
        private LazySingleton(){}
    
        public synchronized static LazySingleton getInstance() {
    
            if(instance == null){
                //在多线程情况下,实例的创建会出现现不一致情况,因此要加synchronized
                instance = new LazySingleton();
            }
            return  instance;
        }
    }
    

      优点:保证了线程安全,只有在被用到的情况下,才会初始化实例,节省了空间
      缺点:synchronized加在了方法上,同步过度,每个线程执行getInstance方法时都要同步,执行效率比较低,最好的情况是只在实例第一次初始化时,执行同步

    3. 双重检查锁

    /**
     * 3-双重检查锁单例模式
     */
    public class Singleton implements Serializable {
    
        private static volatile Singleton instance = null;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
    
            //如果实例已经被创建,则不被同步,这样可以提高执行效率
            if (instance == null) {
    
                //实例初次被创建时,可能有多个线程,所以要加锁,同步
                synchronized (Singleton.class) {
    
                    //实例只可以被创建1次,等其它阻塞线程执行时,不在初始化
                    if (instance == null) {
                    //该赋值操作,只在当前线程的工作区中执行,什么时候会写到主存,由jvm执行,因此要加volatile,让其它线程可知
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    
        //防被反序列化时创建多个实例对象
        private Object readResolve() {
            return getInstance();
        }
    
        //防止通过反射创建多个实例,重写getClass方法
        private static Class getClass(String classname)
                throws ClassNotFoundException {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    
            if (classLoader == null)
                classLoader = Singleton.class.getClassLoader();
    
            return (classLoader.loadClass(classname));
        }
    }
    

      优点:理想很丰满,思路清晰,只在初始化实例时,同步
      缺点:现实很残酷,在java旧版本时,支持的并不很好,原因在于instance = new Singleton()在多线程情况下,可能出现构造方法还没执行,就被其它线程拿走了。现如今violate已被优化,可以实现,但是效率并不高

    4. 静态内部类

    /**
     * 4-内部类单例模式
     */
    public class InnerClassSingleton {
    
        private static class SingletonHolder{
            public static final InnerClassSingleton instance = new InnerClassSingleton();
        }
    
        public static InnerClassSingleton getInstance(){
            return SingletonHolder.instance;
        }
    
    }
    

      优点:由jvm保证线程安全,只有被用到时,才会被初始化
      缺点:序列化和反序列化支持比较差

    5. 枚举类

    /**
     * 5-枚举单例类
     */
    public enum  SingletonEnum {
    
        INSTANCE; //单例实例
        private DataSource dataSource;
        private SingletonEnum(){
    
            //初始化单例的内容,添加dataSource的配置内容
        }
    
        public Connection getConnection() throws SQLException {
            return dataSource.getConnection();
        }
    }
    

      优点:最佳实践,完美解决各种问题
      缺点:项目中运用的少

    后记

      能力有限,如有纰漏,请在评论区指出,老朽虽一把年纪,必当感激涕零,泪如雨下。若有满嘴喷粪撕逼者,一律拉黑、举报。
      转载时,注明出处是人格的一种体现(https://www.zybuluo.com/BertLee/note/837611)。
      撰笔之时,参考了以下几篇博文,如有不妥之处,请与老朽联系。

    http://blog.csdn.net/huangyuan_xuan/article/details/52193006
    http://blog.csdn.net/yangkai_hudong/article/details/50628172
    http://www.cnblogs.com/java-my-life/archive/2012/03/31/2425631.html

  • 相关阅读:
    吕滔博客 --------MYSQL 备份与参数详解
    solaris知识库
    F5 负载均衡
    日志管理 rsyslog服务浅析
    你所不知到的C++ 系列
    php内核探索
    shell 编程中使用到得if语句内判断参数
    linux查看CPU性能及工作状态的指令
    MYSQL 5.7 主从复制 -----GTID说明与限制 原创
    C#:Json数据反序列化为Dictionary并根据关键字获取指定的值
  • 原文地址:https://www.cnblogs.com/codebug/p/7279324.html
Copyright © 2011-2022 走看看