由一个单例模式引发的思考-holder类方式

前言:

最近在看《Java并发编程实践》,里面提到了一种实现单例模式的方式,并大致说明了机制,但仍不是很清晰,今日有空,查阅相关书籍,尝试解释其中道理。

单例模式:

单例模式是一种常用的软件设计模式,它用于确保一个类只有一个实例,并提供一个全局访问点。单例模式通常用于需要频繁实例化且实例化对象消耗较大的情况,例如数据库连接、线程池等。

单例模式的实现方式有多种,包括饿汉式、懒汉式、双重校验锁、静态内部类等。其中饿汉式是指在类加载时就已经实例化对象,懒汉式则是延迟实例化,双重校验锁则是利用volatile关键字和synchronized关键字来保证线程安全。

单例模式的优点是可以避免对资源的多重占用,减少内存开销,同时设置全局访问点,可以优化和共享资源的访问。但是单例模式也存在一些缺点,例如如果要扩展该单例类,除了修改原来的代码,没有第二种途径,违背开闭原则。

总之,单例模式是一种常用的软件设计模式,它可以提高程序的性能和效率,但需要注意线程安全和扩展性问题。

以上来自文心一言。

单例的实现:

一般有懒汉,饿汉,DCL(双检锁),枚举,还有本文的holder,详细对应代码,可自行网上查阅。

类加载时机:

关于在什么情况下需要开始类加载过程的第一个阶段“加载”,《Java虚拟机规范》中并没有进行 强制约束,这点可以交给虚拟机的具体实现来自由把握。但是对于初始化阶段,《Java虚拟机规范》 则是严格规定了有且只有六种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):

1)遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段。能够生成这四条指令的典型Java代码场景有:

        ·使用new关键字实例化对象的时候。

        ·读取或设置一个类型的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外) 的时候。

        ·调用一个类型的静态方法的时候。

2)使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需 要先触发其初始化。

3)当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先 初始化这个主类。

5)当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。

6)当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有 这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

                                                  --  来自《深入理解Java虚拟机:JVM高级特性与最佳实践》

如果觉得难以理解以上,还可以参考下R大的回答:
由一个单例模式引发的思考-holder类方式_第1张图片

书中的代码形式及解释:

书中代码:由一个单例模式引发的思考-holder类方式_第2张图片

由上文可知,在调用ResourceFactory的getResource方法时,首先会加载和初始化本身调用一个类型的静态方法的时候),然后会触发ResourceHolder类加载和初始化读取或设置一个类型的静态字段),再触发Resouce类的加载和初始化使用new关键字实例化对象的时候)。

书中的解释如下:

日常写Holder类的形式及解释:

日常写单例的时候可以下面这种方式:

public class Student{
    private Student() {
    }
   

    private static class Holder{
        public static Student stu = new Student();

    }

    public static Student getInstance() {
        return Holder.stu;
    }


}

Resource相当于Student,在书的例子中:当使用Student类的getInstance方法时,首先会触发Student的加载机制(静态方法),然后会触发Holder内部类的加载(静态变量)。由于Student类已经被加载过了,所以不用再次加载。

你可能感兴趣的:(JVM,设计模式,单例模式,java,jvm)