手撕单例模式——彻底搞懂饿汉式、懒汉式、静态内部类、枚举实现单例,以及通过反射和反序列化破坏单例

本文深入探讨Java中的单例模式,包括饿汉式、懒汉式(DCL)、静态内部类和枚举的实现方式。同时,分析了如何通过反射和反序列化破坏单例,以及如何防止这种破坏,确保单例的唯一性。
摘要由CSDN通过智能技术生成

单例模式的主要作用是保证在Java应用程序中,保证一个类只有一个实例。使用单例的好处由于其限制了类的实例个数,可以节省内存,方便垃圾回收。

​ 单例的应用场景:网站常常会统计当前在线人数,就可以使用一个计数器进行统计,就需要保证这个计数器对象是单例实现的。否则,当多个用户同时登录后获取到不同的计数器对象进行加一,再存储到内存数据库就会导致实际在线人数和统计的在线人数不一致。

单例模式的实现主要可以通过饿汉式、懒汉式(DCL)、静态内部类以及枚举实现。
其中饿汉式、懒汉式、静态内部类皆可以通过反射或序列化的方式破坏单例,而枚举可以有效的防止反射破坏单例。我们在这篇文章从四种单例的创建方式,以及如何破坏单例,如何防止破坏单例三个方面来讲解。

注意:单例中的构造是私有的,只有私有构造器才能防止外部类轻易通过构造方法来创建实例,从而破坏单例。

  1. 饿汉式单例模式
    所谓饿汉式就是直接在实例初始化时,便调用构造方法来创建单例。
public class Hungry {
   
    private Hungry(){
   
    }
    private final static Hungry HUNGRY = new Hungry();

    public static Hungry GetInstance(){
   
        return HUNGRY;
    }
}
  1. 懒汉式
    懒汉式,顾名思义,就是在使用的时候才会创建实例。懒汉式通过双重检测(即在加锁前加锁后判断当前单例是否为null),主要是因为构造方法若涉及到指令重排,会导致返回无效的单例)。
public class Lazy {
   
    private Lazy(){
   
    }
    private static Lazy LAZY;
    public static Lazy GetInstance(){
   
        if(LAZY == null){
   
            // 加锁,双层检测
            synchronized (Lazy.class){
   
                if(LAZY == null){
   
                    LAZY = new Lazy();  // 在操作系统内部并非原子操作
                    // 1.分配内存空间  2.调用构造方法  3.将创建的对象执行分配的内存空间
                }
            }
        }
        return LAZY;
    }
}
  1. 静态内部类实现单例
    静态内部类的单例由内部类创建,由于JVM加载外部类时不会加载内部类,只有当调用静态内部类的方法/属性时,才会加载,并初始化属性。静态属性由于被static修饰,保证只被实例化一次(类加载的最后一步是执行clinit方法,当有多个线程执行初始化方法时,JVM保证只有一个线程可以进入该方法,其他线程进入阻塞,从而保证类的初始化只被执行一次,从而保证只被实例化一次,并且严格保证实例化顺序。
public class StaticInnerClass {
   

    private StaticInnerClass(){
   };

    public static class MyInnerClass{
   
        private static 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值