尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

2. 单例模式怎么创建?(双重检查锁和静态内部类),如何防止反射破坏单例?

2. 单例模式怎么创建?(双重检查锁和静态内部类),如何防止反射破坏单例? 一、什么是单例模式单例Singleton属于创建型设计模式作用保证一个类在整个程序中全局只有唯一一个实例对象并且对外提过一个获取这个唯一实例的方法。简单大白话整个项目不管哪里调用拿到的永远是同一个对象不会重复 new。二、使用的场景1.数据库连接池连接池只需要一份不能到处新建2.线程池全局一份线程池3.配置文件读取类读取配置只加载一次4.工具类、缓存对象目的节省内存、避免重复创建对象保证全局状态统一。三、单例模式的创建1..饿汉式类加载的时候直接把对象创建好。优点天然线程安全简单缺点没有懒加载类加载就创建对象不用也占内存//饿汉 public class Singleton{ private static Singleton instance new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }2.懒汉式用到的时候才创建对象懒加载用到才创建节省内存但是要处理多线程安衍生普通懒汉线程不安全、双重检查锁 DCL、静态内部类。* 特点延迟加载调用方法才创建对象多线程并发会产生多个实例public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance null){ instance new Singleton(); //多线程并发会创建多个对象 } return instance; } }3.同步方法懒汉单例* 特点加synchronized保证线程安全但是每次调用方法都要抢占锁并发性能差class SyncLazySingleton { private static SyncLazySingleton instance; private SyncLazySingleton() {} // synchronized修饰静态方法锁对象为当前类Class对象同一时刻仅一个线程可进入 public static synchronized SyncLazySingleton getInstance() { if (instance null) { instance new SyncLazySingleton(); } return instance; }4.DCL双重检验锁volatile作用禁止CPU指令重排序 new对象底层三步1分配堆内存 2初始化对象 3引用赋值 重排序可能导致3提前执行其他线程拿到半初始化残缺对象volatile杜绝该问题class DCLSingleton { /* volatile作用禁止CPU指令重排序 new对象底层三步1分配堆内存 2初始化对象 3引用赋值 重排序可能导致3提前执行其他线程拿到半初始化残缺对象volatile杜绝该问题 */ private static volatile DCLSingleton instance; private DCLSingleton() {} public static DCLSingleton getInstance() { // 第一次外层判断对象已创建直接返回不用抢锁大幅提升效率 if (instance null) { // 锁定当前类保证同一时间只有一个线程进入创建逻辑 synchronized (DCLSingleton.class) { // 第二次内层判断防止多个线程卡在锁外唤醒后重复创建对象 if (instance null) { instance new DCLSingleton(); } } } return instance; } }5.枚举public enum Singleton { //唯一实例 INSTANCE; //自己的业务方法 public void test(){ System.out.println(枚举单例执行); } }原理:枚举实例在类加载阶段就初始化不是懒加载JVM 保证枚举实例只能实例化一次天然线程安全底层是 classINSTANCE 是 public static final 的常量。为什么枚举可以防反射破坏单例:反射调用newInstance()创建对象时JDK 源码会判断如果当前类是枚举类型直接抛出 IllegalArgumentException: Cannot reflectively create enum objects直接禁止反射 new 出枚举对象所以反射无法破坏。DCL、静态内部类的私有构造可以被反射暴力调用 setAccessible (true) 创建新对象枚举直接封死这条路。防序列化破坏普通单例实现如果实现 Serializable 序列化接口反序列化会生成全新对象破坏单例。枚举序列化、反序列化由 JVM 特殊处理永远返回同一个 INSTANCE 实例不会产生新对象。实现单例最佳方式就是枚举实现懒加载线程安全防反射防序列化饿汉式❌✅❌❌DCL 双重检查锁✅✅❌❌静态内部类✅✅❌❌枚举单例❌✅✅✅
返回列表