• 【JVM】为什么静态内部类实现单例模式是线程安全?


    首先给出代码:

    1. //基于类初始化的线程安全的单例
    2. class SingleTon4{
    3. private SingleTon4(){}
    4. private static class InnerClass{
    5. private static SingleTon4 instance= new SingleTon4();
    6. }
    7. public static SingleTon4 getInstance(){//如果没有到这里,那么不会加载上面的内部类
    8. return InnerClass.instance; //这里将导致InstanceHolder类被初始化
    9. }
    10. }


    静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。具体来说当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,使用INSTANCE的时候,才会导致虚拟机加载SingleTonHoler类。这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

    那么他是如何实现线程安全的?        
    首先要了解类加载过程中的最后一个阶段:即类的初始化,类的初始化阶本质就是执行类构造器的方法。

            方法:这不是由程序员写的程序,而是根据代码由javac编译器生成的。它是由类里面所有的类变量的赋值动作和静态代码块组成的。JVM内部会保证一个类的方法在多线程环境下被正确的加锁同步,也就是说如果多个线程同时去进行“类的初始化”,那么只有一个线程会去执行类的方法,其他的线程都要阻塞等待,直到这个线程执行完方法。然后执行完方法后,其他线程唤醒,但是不会再进入()方法。也就是说同一个加载器下,一个类型只会初始化一次。

            那么回到这个代码中,这里的静态变量的赋值操作进行编译之后实际上就是一个代码,当我们执行getInstance方法的时候,会导致SingleTonHolder类的加载,类加载的最后会执行类的初始化,但是即使在多线程情况下,这个类的初始化的代码也只会被执行一次,所以他只会有一个实例。

            那么再增加一句,之所以这里变量定义的时候不需要volatile,因为只有一个线程会执行具体的类的初始化代码,也就是即使有指令重排序,因为根本没有第二个线程给你去影响,所以无所谓。

            此外,如果讲得再细致一点,可以参考下面的第二个网站,简单说一下:

            比如有一个类T,那么什么时候会进行类T的初始化?有以下5种情况:

    •     T 是一个类,而且一个 T 类型的实例被创建;
    •     T 是一个类,且 T 中声明的一个静态方法被调用;
    •     T 中声明的一个静态字段被赋值;
    •     T 中声明的一个静态字段被使用,而且这个字段不是一个常量字段;
    •     T 是一个顶级类(top level class,见 java 语言规范的§7.6),而且一个断言语句嵌套在 T 内部被执行。

            而我们前面的代码则对应了第四种情况,一个静态字段被使用,因此此时则会进行静态内部类的初始化。又因为java是多线程语言,作者也考虑到了可能存在“多个线程在同一时间尝试去初始化同一个类”的情况,因此java规定,对于每一个类或接口 C,都有一个唯一的初始化锁 LC 与之对应。

            JVM 在类初始化期间会获取这个初始化锁,并且每个线程至少获取一次锁来确保这个类已经被初始化过了。(但是只有第一个获得锁的线程,会执行初始化,执行完之后会设置一个标志位,表示已经初始化完成,后面其他的线程再次获得锁,检查标志位,发现已经初始化完了,直接释放锁,不会再次执行初始化。)

    参考:https://blog.csdn.net/qq_35590091/article/details/107348114

    《深入理解JAVA虚拟机》 

  • 相关阅读:
    2.DApp-编写和运行solidity智能合约
    SV-线程的使用与控制
    Build Data Visualization Apps
    我的Go+语言初体验——祝福留言小系统,让她也可以感受到你的祝福
    记一次公司被勒索病毒攻击事迹,上上下下咬牙切齿
    网关与auth微服务缓存打通
    SpringBoot启动流程源码分析
    (附源码)ssm心理咨询服务平台 毕业设计 324615
    Elasticsearch学习(一)
    前端面试题整理——webpack相关考点
  • 原文地址:https://blog.csdn.net/m0_73499047/article/details/132989383