单例模式是就是在系统运行时,我们希望类生成的对象就一个,类实例化只能时一样,比如线程池、缓存等,我们在系统运行如果缓存或线程池变化,可能会造成系统出现异常,资源过度浪费。
单例模式的定义:
确保一个类只能有一个实例,并提供一个全局访问点。
单例模式分为两种,一种是不安全的单例模式(我们需要废弃),第二种是线程安全的单例模式。下面列举几种单例模式的实现。
1。饿汉式
2。同步方法-懒汉式
3。同步代码块-懒汉式
4。双重检查锁
5。枚举类
6。静态内部类
7。静态枚举类
---
使用单例模式注意三大条件:
1.私有化构造器,
2.类含有静态私有对象,
3.提供公共静态的方法创建或获取私有对象的值。
---
使用单例
优点:
1.在内存中只有一个实例对象,减少频繁创建销毁对象实例的内存开销;
2.避免对资源的过度占用。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类只应该关系内部逻辑而不应该关系外部怎样实例化。
使用场景:
1.唯一的序列号
2.WEB中的计数器
3.创建一个对象消耗的资源过多
1. 饿汉式代码
/** * 单例模式:饿汉式 */ public class SingletonDemo01 { //类初始化立即加载,由于类加载时完成初始化,线程安全。不用同步快,调用效率高。 private static SingletonDemo01 instance = new SingletonDemo01(); private SingletonDemo01() { } public static SingletonDemo01 getInstance() { return instance; } }
2. 懒汉式 同步方法
/** * 单例模式:懒汉式线程安全 */ public class SingletonDemo03 { //类初始化延迟加载,方法同步线程安全,调用效率低。 private static SingletonDemo03 instance = null; private SingletonDemo03() { } public static synchronized SingletonDemo03 getInstance() { if (instance == null) { instance = new SingletonDemo03(); } return instance; } }
3. 懒汉式同步方法
/** * 单例模式:懒汉式双重检查锁 */ public class SingletonDemo04 { //由于编译器优化和JVM内部模型原因,同步块会有问题,会出现问题 private static SingletonDemo04 instance = null; private SingletonDemo04() { } public static SingletonDemo04 getInstance() { if (instance == null) { synchronized (SingletonDemo04.class) { if (instance == null) { instance = new SingletonDemo04(); } } } return instance; } }
4.静态内部类
/** * 单例模式:静态内部类懒加载 */ public class SingletonDemo05 { //外部没有static属性,不会立即加载对象 //真正调用getInstance,才会加载内部类 //高效+安全+延迟加载 private static class SingletonInstance { public static SingletonDemo05 instance = new SingletonDemo05(); } private SingletonDemo05() { } public static SingletonDemo05 getInstance() { return SingletonInstance.instance; } }
5. 枚举类
/** * 单例模式:枚举类 */ public enum SingletonDemo06 { //直接用SingletonDemo06.INSTANCE本身代理,代表一个对象 //避免反射、反序列化,效率高 //没有懒加载 INSTANCE; Enum ss; }
6. 枚举类实现懒加载
/** * 单例模式:枚举类实现懒加载 */ public class SingletonDemo08 { // 私有构造函数 private SingletonDemo08() { } public static SingletonDemo08 getInstance() { return Singleton.INSTANCE.getInstance(); } private enum Singleton { INSTANCE; private SingletonDemo08 singleton; // JVM保证这个方法绝对只调用一次 Singleton() { singleton = new SingletonDemo08(); } public SingletonDemo08 getInstance() { return singleton; } } }
7.解决反射漏铜和序列化漏铜
import java.io.ObjectStreamException; import java.io.Serializable; /** * 单例模式:解决反射漏铜,通过设置constructor.setAccessible(true);//跳过权限校验,是的创建实例不一致 * 解决序列化漏铜,readResolve() */ public class SingletonDemo07 implements Serializable { //类初始化延迟加载,方法同步线程安全,调用效率低。 private static SingletonDemo07 instance = null; private SingletonDemo07() { if (instance != null) {//防止通过反射破解单例 throw new RuntimeException(); } } public static synchronized SingletonDemo07 getInstance() { if (instance == null) { instance = new SingletonDemo07(); } return instance; } //反序列化时,直接返回此对象,而不生成新对象 private Object readResolve() throws ObjectStreamException { return instance; } }