Advertisement

为什么enum枚举实现单例模式天然线程安全?

阅读量:

当定义枚举时与使用 class 类似 使用 enum 是 Java 中的一个核心概念 。 类似于 class 对应一个 Class 类 这样的方式 enum 同样对应一个 Enum 类
经过反编译已经确定 当我们为已定义好的枚举生成代码时 系统会将其编译为形如 public final class T extends Enum 的形式 。
此外 枚举项之间的关系依靠 static 关键字来实现定义 。

复制代码
    public enum T {
    	SPRING,SUMMER,AUTUMN,WINTER;
    }

反编译后代码为:

复制代码
    public final class T extends Enum 
    {
    	//省略部分内容
    	public static final T SPRING;
    	public static final T SUMMER;
    	public static final T AUTUMN;
    	public static final T WINTER;
    	private static final T ENUM$VALUES[];枚举类型和泛型 < 228
    	static
    	{
    		SPRING = new T("SPRING", 0);
    		SUMMER = new T("SUMMER", 1);
    		AUTUMN = new T("AUTUMN", 2);
    		WINTER = new T("WINTER", 3);
    		ENUM$VALUES = (new T[] {
    		SPRING, SUMMER, AUTUMN, WINTER
    	});
    	}
    }
  1. 自定义枚举类型T不能被继承
    2.T的所有属性全部由static final修饰,并自动具备多线程能力,其原因在于这些属性都具有静态的最终性特征

熟悉JVM类加载机制的朋友通常会对相关内容较为熟悉。
static类型的属性会在类加载过程中进行初始化。
当Java类首次被实际调用时会触发静态资源的初始化过程。
需要注意的是:
Java类及其相关初始化操作均经过严格的线程保护机制确保。
具体来说:
由于虚拟机在执行动态反射时会调用ClassLoader.loadClass方法。
该方法通过同步机制实现了对多线程环境的安全性保障。

所以, 创建一个 enum 类型是线程安全的。

具体来说,在我们的设计中,默认情况下会为每个进程创建一个实例,并且在首次被实际调用时会进入内核态进行初始化操作,并确保该初始化操作具有线程安全特性。

而我们知道,在解决单一实例的并发处理中,核心任务是确保初始化时的线程安全性

所以, 由于枚举的以上特性, 枚举实现的单例是天生线程安全 的。

同时,enum单例模式也支持序列化/反序列化

在序列化的时候 Java 仅仅是将枚举对象的 name 属性 输出到结果中,

在反序列化过程中,则是借助于Java API中的Enum类提供的valueOf函数来通过名称获取对应的枚举实例

同时,在编译器层面也被设置了严格的限制措施以防止任何对这种序列化机制的修改**(即禁止自定义序列化过程)**。基于此原则,默认情况下已禁用了以下关键方法:包括以下方法:writeObject、readObject、readObjectNoData、writeReplace和readResolve等技术手段以确保系统的稳定性和数据完整性

全部评论 (0)

还没有任何评论哟~