本文介绍了关于“java枚举如何确保线程安全”的知识。很多人在实际案件操作中都会遇到这样的困难。接下来,让边肖带领大家学习如何应对这些情况!希望大家认真阅读,学点东西!
枚举是如何保证线程安全的
要想看到源代码,首先要有一个类,那么枚举类型是什么呢?是枚举吗?答案显然不是。enum只是一个关键字,就像class一样。它不是一个类。那么枚举由哪个类维护呢?让我们简单地写一个枚举:
公共枚举t {SPRING,SUMMER,FAULT,WINTER}
然后我们使用反编译来看看这段代码是如何实现的。反编译(Java的反编译)后,代码内容如下:
公共最终类T扩展了Enum {私有T(String s,int i){super(s,I)};}公共静态T[]值(){ T at[];int I;t at 1[];system . array copy(at=ENUM $ VALUES,0,at1=new T[i=at.length],0,I);在1点返回;}公共静态T值Of(字符串){return (T)Enum.valueOf(演示/T,s);}公共静态最终T SPRING公开静态决赛T SUMMER大众静态决赛T fault;公共静态决赛T WINTER私有静态最终T ENUM $ VALUES[];静态{SPRING=新T('SPRING ',0);SUMMER=新T('SUMMER ',1);秋=新T('秋',2);WINTER=新T('WINTER ',3);ENUM$VALUES=(new T[] {SPRING,SUMMER,秋,冬});}}
从反编译的代码中我们可以看到,公共最终类T扩展Enum表明这个类继承了Enum类,而final关键字告诉我们这个类也不能继承。当我们使用穆恩定义枚举类型时,编译器会自动帮助我们创建一个继承枚举类的最终类型类,因此枚举类型不能被继承。我们看到这个类中有几个属性和方法。
我们可以看到:
公共静态最终T SPRING公开静态决赛T SUMMER大众静态决赛T fault;公共静态决赛T WINTER私有静态最终T ENUM $ VALUES[];静态{SPRING=新T('SPRING ',0);SUMMER=新T('SUMMER ',1);秋=新T('秋',2);WINTER=新T('WINTER ',3);ENUM$VALUES=(new T[] {SPRING,SUMMER,秋,冬});}
它们都是静态类型的,因为静态类型的属性将在类加载后初始化。我们在两篇文章中分别介绍了对Java的类加载器机制(源代码级)和Java类加载、链接和初始化的深入分析。当一个Java类第一次实际使用时,静态资源被初始化,Java类的加载和初始化过程是线程安全的。因此,创建枚举类型是线程安全的。
为什么用枚举实现的单例是最好的方式
在[注] singleton pattern的七种编写方法中,我们可以看到实现singleton的方法有七种。其中,Effective Java作者Josh Bloch提倡使用枚举。既然大神说这种方式好,我们就要知道为什么好。
1. 枚举写法简单
简单的写作。让我们来看看singleton pattern的七种编写方法的实现,以了解它们之间的区别。
公共枚举EasySingleton { INSTANCE}
您可以通过EasySingleton访问它。情况
2. 枚举自己处理序列化
我们知道,以前所有的singleton模式都有一个很大的问题,那就是一旦实现了Serializable接口,它就不再是singleton了,因为对readObject()方法的每次调用都会返回一个新创建的对象,一种解决方案是使用readResolve()方法来避免这种情况。
但是,**为了保证Java规范中所述的枚举类型在JVM中是唯一的,Java对枚举类型的序列化和反序列化做了特殊的规定。
序列化时,Java只将枚举对象的name属性输出到结果中,而反序列化时,则使用java.lang.Enum的valueOf方法按名称查找枚举对象。
同时,编译器不允许对这种序列化机制进行任何自定义,因此禁用了writeObject、readObject、readObjectNoData、writeReplace readResolve等方法。让我们看看这个方法的价值:
公共静态T扩展了EnumT T valueOf(ClassT enumType,String name) { T结果=enum type . enumconstanntdirectory()。get(name);如果(结果!=null)返回结果;if (name==null)抛出新的NullPointerException('Name为null ');引发新的IllegalArgumentException('无枚举常量'枚举类型' '姓名);}
从代码中可以看到,代码将尝试通过调用Class对象enumType的enumConstantDirectory()方法从返回的映射中获取名为name的枚举对象,如果它不存在,将引发异常。
进一步遵循enumconstatdirectory()方法,你会发现最后会以反射的方式调用enumType静态值()方法,也就是我们上面看到的编译器为我们创建的方法,然后enumconstatdirectory对象中的enumconntdirectory属性会被返回的结果填充。
因此,JVM保证了序列化。
3.枚举实例创建是thread-safe(线程安全的)
当第一次实际使用Java类时,静态资源被初始化,加载和初始化Java类的过程是线程安全的。因此,创建枚举类型是线程安全的。
这里介绍一下“java枚举如何保证线程安全”的内容。感谢您的阅读。如果你想了解更多的行业,可以关注网站。边肖将为您输出更多高质量的实用文章!
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/105117.html