枚举单例避免线程不同步、反射攻击和序列化攻击的原理总结

引言

最近在学习单例模式的多种实现方法,单例的重点有4个:

1.是否懒加载

2.是否线程同步

3.反射攻击

4.序列化攻击

其中枚举单例除了不能懒加载,可以实现线程同步,防止反射攻击和序列化攻击。

大部分的博客,只是用代码论证了枚举单例确实避免了这些问题,却并未完整说出这3个问题是如何避免的,只说出了其中的一两个,所以我经过漫长的资料查找后,终于整理出了总结。

枚举单例写法

——《Effective Java》

enum SingletonDemo{
    INSTANCE;
    public void otherMethods(){
        System.out.println("Something");
    }
}

如何避免线程不同步?

枚举类编译后,所有的枚举变量都是static,通过类加载机制实现线程同步。

如何避免反射攻击?

反射无法通过newInstance调用构造器来创建新的枚举类实例。(详细请参考为什么要用枚举实现单例模式(避免反射、序列化问题)

如何避免序列化攻击?

Java规范字规定,每个枚举类型及其定义的枚举变量在JVM中都是唯一的,因此在枚举类型的序列化和反序列化上,Java做了特殊的规定。

在序列化的时候Java仅仅是将枚举对象的name属性输到结果中,反序列化的时候则是通过java.lang.Enum的valueOf()方法来根据名字查找枚举对象。

比如说,序列化的时候只将DATASOURCE这个名称输出,反序列化的时候再通过这个名称,查找对应的枚举类型,因此反序列化后的实例也会和之前被序列化的对象实例相同。(详细请参考枚举单例 最安全的单例,可以有效防止反射,序列化

public enum DataSourceEnum {
    DATASOURCE;
}  

引用

为什么要用枚举实现单例模式(避免反射、序列化问题)

枚举单例 最安全的单例,可以有效防止反射,序列化

单例模式推荐写法--枚举实现单例

Java枚举enum以及应用:枚举实现单例模式

猜你喜欢

转载自www.cnblogs.com/ledphz/p/12439694.html