单例模式的定义
单例模式是指确保一个类在任何情况下都只有一个实例,并且提供一个访问该单例的全局访问点。
如何创建一个单例模式
构造函数需要是 private 访问权限的,这样才能避免外部通过 new 创建实例;
考虑对象创建时的线程安全问题;
考虑是否支持延迟加载;
考虑 getInstance() 的性能(是否加锁)
单例模式适用的场景
J2EE 标准中的 ServletContext 和 ServletContextConfig;
Spring 框架应用中的 ApplicationContext、数据库中的连接池等也都是单例模式。
单例模式的分类
饿汉式单例
优点:在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的,执行效率高,性能好,没有锁。
缺点:因为不支持延迟加载,如果实例占用资源多(比如占用内存多)或初始化耗时长(比如需要加载各种配置文件),提前初始化实例是一种浪费资源的行为。
懒汉式单例(DCL)
优点:支持延迟加载,节省内存,线程安全。
缺点:代码可读性差,可通过反射破坏单例模式。
静态内部类(单例)
优点:使用时才会加载,而且静态内部变量只加载一次所以线程安全,性能高,避免了内存浪费。
缺点:代码不够优雅
枚举类(单例)
优点:线程安全,不用担心反射破坏单例模式,性能高,没有任何锁。
缺点:枚举类占用内存多。
ThreadLocal(单例)
优点:通过线程隔离实现线程安全,性能高。
缺点:同个线程下的单例,以空间换时间
破坏单例模式的方法
通过反射破坏单例,可通过修改构造方法解决;
通过序列化和反序列化破坏单例,可通过增加readResolve()方法解决,如下图: