当前位置: 代码迷 >> 综合 >> Java 中 Holder 方式 和 枚举方式 实现单例模式
  详细解决方案

Java 中 Holder 方式 和 枚举方式 实现单例模式

热度:50   发布时间:2023-12-26 12:52:23.0

 Holder 方式 和 枚举方式 可以线程安全的实现单例模式。

 Holder 方式 借助于类加载 的初始化阶段<clinit>() 方法是同步方法。

枚举方式 是因为枚举类型不能继承且只能被实例化一次。

1. Holder 方式实现单例模式

类加载 的初始化阶段<clinit>() 方法是同步方法,在类中设置一个静态类,将唯一实例放在静态类中,第一次访问实例的时候内部类初始化,即初始化唯一实例。代码如下所示:

public final class HolderSingleton {// 实例变量private String value;private HolderSingleton() {System.out.println("初始化");}// 静态内部类持有实例,并可直接被初始化private static class Holder {private static HolderSingleton instance = new HolderSingleton();}public static HolderSingleton getInstance() {return Holder.instance;}public static void main(String[] args) {HolderSingleton holderSingleton1 = HolderSingleton.getInstance();HolderSingleton holderSingleton2 = HolderSingleton.getInstance();System.out.println(holderSingleton1 == holderSingleton2);}
}

测试截图如下所示:

2. 枚举方式实现单例模式

枚举类型不能继承且只能被实例化一次,枚举方式实现单例模式如下所示。

package Singleton;public enum EnumSingleton {INSTANCE;private String value;EnumSingleton() {System.out.println("初始化");}//    public static void method() {
//
//    }public static EnumSingleton getInstance() {return INSTANCE;}public static void main(String[] args) {//EnumSingleton.method();EnumSingleton enumSingleton1 = EnumSingleton.getInstance();EnumSingleton enumSingleton2 = EnumSingleton.getInstance();System.out.println(enumSingleton1 == enumSingleton2);}
}

测试运行截图:

调用静态方法就会导致唯一实例初始化,测试代码如下所示。

package Singleton;public enum EnumSingleton {INSTANCE;private String value;EnumSingleton() {System.out.println("初始化");}public static void method() {}public static EnumSingleton getInstance() {return INSTANCE;}public static void main(String[] args) {EnumSingleton.method();}
}

虚拟机规范有且只有下面5种情况立即对类进行“初始化”。

(1) 使用 new 关键字 ;Get static,Put static 即设置或访问静态变量 (类的静态字段 被 final 修饰,加入常量池的除外);Invoke static 调用静态方法 。

(2)使用 java.lang.reflect 包的方法对类进行反射的时候。

(3)初始一个类,发现父类没有进行初始化,先初始化父类。

(4)虚拟机启动时, 用户需要制定一个要执行的主类,先初始化主类。

(5)Java 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic、REF_setStatic、REF_invokeStatic 方法的句柄,并且该句柄的方法所对应类没有进行过初始化,则需要先触发其初始化。

参考文献

  • Java高并发编程详解:多线程与架构设计 / 汪文君著——北京:机械工业出版社,2018.5
  • 深入理解Java虚拟机:JVM高级特性与最佳实践 / 周志明著. —— 2 版 . —— 北京:机械工业出版社,2013.6 (2019.1重印)
  相关解决方案