设计模式 | 挑战单例模式(四)

本文探讨了静态内部类在单例模式中的应用,利用JVM类初始化机制实现延迟加载并确保多线程下的线程安全。讲解了原理和潜在的局限性,并提及其他可能的解决方案如双重检查锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


theme: channing-cyan

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

内容接着上篇文章《挑战单例模式(三)》,上篇文章讲到了双重检查锁单例实现方式,这篇文章来使用最广泛的静态内部类单例实现方式。

五、静态内部类

静态内部类的解决方案用到了JVM中类初始化的机制。它既保证延迟加载,避免内存浪费,又能兼顾性能同时保证线程安全,多线程环境下,只创建一个实例对象。

静态内部类实现方式如下:

public class SingletonInInnerClass {   private SingletonInInnerClass(){} ​   public static SingletonInInnerClass getInstance(){       return Holder.INSTANCE;   } ​   private static class Holder{       private static final SingletonInInnerClass INSTANCE = new SingletonInInnerClass();   } }

当加载SingletonInInnerClass单例类时,内部类不会被加载,因为在加载单例类的时候不会创建对象,只有再调用getInstance静态方法时才创建内部类,这个单例类的懒加载。目前是使用的最广泛的单例类创建形式了。

那么实现的原理是什么?简单地说,巧妙地用到了内部类一定是要在方法调用之前初始化。即外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故在需要用到实例化对象时,才创建对象。

JVM如何保证内部类只是被初始化一次?这个要从类的加载机制说起, JVM会保证一个类的clinit()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的clinit()方法,其他线程都需要阻塞等待,直到活动线程执行clinit()方法完毕。同一个类加载器下,一种类型只会初始化一次。

那是不是用静态内部类就高枕无忧了呢?它也有一个比较隐秘的缺点那就是由于是静态内部类的形式去创建单例的,故外部无法传递参数进去。这时唯有退而求其次,只能选择双重检查锁模式模式了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值