Singleton(单例)模式

Singleton(单例)模式

  • 概念

    • 顾名思义就是该类只有一个实例,并且确保在任何情况下都绝对只有一个实例,并且程序上也要表现出“只存在一个实例”
  • 优点

    • 只有一个对象,节省内存
    • 可以实现避免对资源的多重占用
    • 在系统设置全局访问点,优化和共享资源访问
  • 实现思路

    • 静态化实例对象
    • 私有构造方法,禁止使用构造器方法来创建实例
    • 提供一个公共静态方法,用来返回唯一实例
  • 适用场景

    • 需要频繁实例化后销毁的对象
    • 创建对象时耗时过多或者耗资源过多,但又经常使用到的对象
    • 有状态的工具类对象
    • 频繁访问数据库或文件的对象
    • 资源共享的情况下,避免优化资源操作时导致的性能损耗等,如日志文件、应用配置
    • 控制资源的情况下,方便资源之间的互相通信,如线程池
  • 懒汉式

    • 懒汉式的意思就是只有当时候的时候采取创建实例,比较“懒”
    • 这种方式当多线程使用时,就存在线程安全问题,可能同时调用getInstance(),创建出多个实例
    public class Singleton{
        private static Singleton singleton;
        //设置构造函数为私有,避免外部通过new来创建对象,保证只有一个接口去创建对象
        private Singleton(){}
        //并且只创建一个对象
        public static Singleton getInstance(){
            if(singleton == null){
                instance = new Singleton();
            }
            return singleton;
        }
    }
    

    为了考虑线程安全问题,因此使用Synchronized关键字来解决

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

    这种方式虽然确保了线程安全,但是可能会引起大量的阻塞,影响性能

  • 饿汉式

    • 饿汉式的意思就是在初始化时已经生成好实例,使用的时候直接返回即可了,比较“勤“,所以容易”饿“
    • 这种方式存在一个问题就是不管有没有用到,都先生成实例,虽然没有线程安全问题,但是会浪费内存空间
    public class Singleton{
        private static Singleton singleton = new Singleton;
        private Singleton(){}
        public static Singleton getInstance(){
            return singleton;
        }
    }
    
  • 双重校验

    • 双重校验也是一种延迟加载,但是通过双重校验解决了线程安全的时候效率低下的问题
    • 这种方法和懒汉式加Synchronized关键字的方法对比,仅仅对一部分代码加了锁,并不是所有调用这个方法的对象都会发生阻塞,只有第一次判断为null时,才进入同步代码块,并且再里面会再一次进行判断,如果其他线程已经创建了,那么就可以直接返回了
    public class Singleton{
        private static Singleton singleton;
        private Singleton(){}
        public static  Singleton getInstance(){
            if(singleton == null){
                synchronized(Singleton.class){
                    if(singleton == null){
                        instance = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }
    
  • 静态内部类方式

    • Java静态内部类的特性是,加载的时候不会加载静态内部类,到使用的时候才会加载
    • 采用静态内部类的方式,只有使用的时候才加载,并且此时的类加载又是线程安全的
    public class Singleton{
        private static class SingletonInner{
            private static Singleton singleton = new Singleton();
        }
        private Singleton(){}
        public static Singleton getInstance(){
            return SingletonInner.singleton;
        }
    }
    
  • 枚举方式

    • 枚举提供了一种方式可以取代大量的static final类型的变量。
    • 枚举方式实现了Serializable接口,所以不用考虑序列化的问题
    • JVM能确保只加载一个实例,来保证线程安全。
    public class Singleton{
        private Singleton(){}
        private enum SingletonEnum{
    		SINGLETON;
            private final Singleton singleton;
            SingletonEnum(){
                singleton = new Singleton();
            }
            private Singleton getInstance(){
                return singleton;
            }
    	}
        public static Singleton getInstance(){
            return SingletonEnum.SINGLETON.getInstance();
        }
    }
    
    
  • 破坏单例模式的方法及解决办法

    • 除了枚举方式外,其他方法都可以通过反射来破坏单例模式,因此可以在构造方法中进行判断,如果已经有实例,则阻止生成新的实例。
    • 如果单例实现了序列化接口Serializable,就可以通过反序列化来破坏单例,所以可以不实现序列化接口,如果非得实现序列化接口,可以重写反序列化方法readResolve(),反序列化时直接返回相关对象。
  • 参考文献

    https://zhuanlan.zhihu.com/p/80127173

    https://blog.csdn.net/absolute_chen/article/details/93380566

    《图解设计模式》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值