欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java枚舉是如何保證線程安全的

 更新時間:2019年06月25日 15:12:43   作者:hollischuang  
這篇文章主要介紹了java枚舉是如何保證線程安全的。Java SE5提供了一種新的類型-Java的枚舉類型,關(guān)鍵字enum可以將一組具名的值的有限集合創(chuàng)建為一種新的類型,而這些具名的值可以作為常規(guī)的程序組件使用,這是一種非常有用的功能。,需要的朋友可以參考下

前言

寫在前面:Java SE5提供了一種新的類型-Java的枚舉類型,關(guān)鍵字enum可以將一組具名的值的有限集合創(chuàng)建為一種新的類型,而這些具名的值可以作為常規(guī)的程序組件使用,這是一種非常有用的功能。本文將深入分析枚舉的源碼,看一看枚舉是怎么實現(xiàn)的,他是如何保證線程安全的,以及為什么用枚舉實現(xiàn)的單例是最好的方式。

枚舉是如何保證線程安全的

要想看源碼,首先得有一個類吧,那么枚舉類型到底是什么類呢?是enum嗎?答案很明顯不是,enum就和class一樣,只是一個關(guān)鍵字,他并不是一個類,那么枚舉是由什么類維護的呢,我們簡單的寫一個枚舉:

public enum t {
SPRING,SUMMER,AUTUMN,WINTER;
}

然后我們使用反編譯,看看這段代碼到底是怎么實現(xiàn)的,反編譯(Java的反編譯)后代碼內(nèi)容如下:

public final class T extends Enum
{
private T(String s, int i)
{
super(s, i);
}
public static T[] values()
{
T at[];
int i;
T at1[];
System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);
return at1;
}
public static T valueOf(String s)
{
return (T)Enum.valueOf(demo/T, s);
}
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[];
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
});
}
}

通過反編譯后代碼我們可以看到,public final class T extends Enum,說明,該類是繼承了Enum類的,同時final關(guān)鍵字告訴我們,這個類也是不能被繼承的。當我們使用enmu來定義一個枚舉類型的時候,編譯器會自動幫我們創(chuàng)建一個final類型的類繼承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[];
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
});
}

都是static類型的,因為static類型的屬性會在類被加載之后被初始化,我們在深度分析Java的ClassLoader機制(源碼級別)和Java類的加載、鏈接和初始化兩個文章中分別介紹過,當一個Java類第一次被真正使用到的時候靜態(tài)資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創(chuàng)建一個enum類型是線程安全的。

為什么用枚舉實現(xiàn)的單例是最好的方式

在[轉(zhuǎn)+注]單例模式的七種寫法中,我們看到一共有七種實現(xiàn)單例的方式,其中,Effective Java作者Josh Bloch 提倡使用枚舉的方式,既然大神說這種方式好,那我們就要知道它為什么好?

1. 枚舉寫法簡單

寫法簡單這個大家看看[轉(zhuǎn)+注]單例模式的七種寫法里面的實現(xiàn)就知道區(qū)別了。

public enum EasySingleton{
INSTANCE;
}

你可以通過EasySingleton.INSTANCE來訪問。

2. 枚舉自己處理序列化

我們知道,以前的所有的單例模式都有一個比較大的問題,就是一旦實現(xiàn)了Serializable接口之后,就不再是單例得了,因為,每次調(diào)用 readObject()方法返回的都是一個新創(chuàng)建出來的對象,有一種解決辦法就是使用readResolve()方法來避免此事發(fā)生。

但是,**為了保證枚舉類型像Java規(guī)范中所說的那樣,每一個枚舉類型極其定義的枚舉變量在JVM中都是唯一的,在枚舉類型的序列化和反序列化上,Java做了特殊的規(guī)定。原文如下:

Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form. To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.lang.Enum.valueOf method, passing the constant's enum type along with the received constant name as arguments. Like other serializable or externalizable objects, enum constants can function as the targets of back references appearing subsequently in the serialization stream. The process by which enum constants are serialized cannot be customized: any class-specific writeObject, readObject, readObjectNoData, writeReplace, and readResolve methods defined by enum types are ignored during serialization and deserialization. Similarly, any serialPersistentFields or serialVersionUID field declarations are also ignored--all enum types have a fixedserialVersionUID of 0L. Documenting serializable fields and data for enum types is unnecessary, since there is no variation in the type of data sent.

大概意思就是說,在序列化的時候Java僅僅是將枚舉對象的name屬性輸出到結(jié)果中,反序列化的時候則是通過java.lang.Enum的valueOf方法來根據(jù)名字查找枚舉對象。

同時,編譯器是不允許任何對這種序列化機制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。 我們看一下這個valueOf方法:

public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) { 
T result = enumType.enumConstantDirectory().get(name); 
if (result != null) 
return result; 
if (name == null) 
throw new NullPointerException("Name is null"); 
throw new IllegalArgumentException( 
"No enum const " + enumType +"." + name); 
} 

從代碼中可以看到,代碼會嘗試從調(diào)用enumType這個Class對象的enumConstantDirectory()方法返回的map中獲取名字為name的枚舉對象,如果不存在就會拋出異常。

再進一步跟到enumConstantDirectory()方法,就會發(fā)現(xiàn)到最后會以反射的方式調(diào)用enumType這個類型的values()靜態(tài)方法,也就是上面我們看到的編譯器為我們創(chuàng)建的那個方法,然后用返回結(jié)果填充enumType這個Class對象中的enumConstantDirectory屬性。

所以,JVM對序列化有保證。

3.枚舉實例創(chuàng)建是thread-safe(線程安全的)

當一個Java類第一次被真正使用到的時候靜態(tài)資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創(chuàng)建一個enum類型是線程安全的。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java中刪除文件/文件夾的3種方法示例小結(jié)

    java中刪除文件/文件夾的3種方法示例小結(jié)

    這篇文章主要介紹了java中刪除文件/文件夾的3種方法示例小結(jié),第一種是通過io刪除文件,第二種是通過Files.walk刪除文件,第三種是通過 Files.walkFileTree刪除文件,本文結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2023-10-10
  • Java內(nèi)存模型JMM詳解

    Java內(nèi)存模型JMM詳解

    這篇文章主要介紹了Java內(nèi)存模型JMM詳解,涉及volatile和監(jiān)視器鎖,final字段,內(nèi)存屏障等相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • java selenium教程環(huán)境搭建基于Maven

    java selenium教程環(huán)境搭建基于Maven

    本文主要介紹Java selenium 環(huán)境的安裝,這里介紹了基于Maven的環(huán)境搭建,有需要的小伙伴可以參考下
    2016-08-08
  • 深入講解我們說的CAS自旋鎖到底是什么

    深入講解我們說的CAS自旋鎖到底是什么

    這篇文章主要給大家介紹了關(guān)于我們說的CAS自旋鎖到底是什么的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-05-05
  • Java?LocalDateTime常用操作方法

    Java?LocalDateTime常用操作方法

    這篇文章主要介紹了Java?LocalDateTime實用方法,Java8提供了新的時間接口LocalDateTime,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-01-01
  • AsyncHttpClient的TimeoutTimerTask連接池異步超時

    AsyncHttpClient的TimeoutTimerTask連接池異步超時

    這篇文章主要為大家介紹了AsyncHttpClient的TimeoutTimerTask連接池異步超時源碼流程解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Java中spring boot validation自定義注解使用方式

    Java中spring boot validation自定義注解使用方式

    這篇文章主要介紹了Java中spring boot validation自定義注解使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Serializable接口的作用_動力節(jié)點Java學院整理

    Serializable接口的作用_動力節(jié)點Java學院整理

    這篇文章主要為大家詳細介紹了java中Serializable接口的作用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Springboot使用@Valid 和AOP做參數(shù)校驗及日志輸出問題

    Springboot使用@Valid 和AOP做參數(shù)校驗及日志輸出問題

    這篇文章主要介紹的Springboot使用@Valid 和AOP做參數(shù)校驗及日志輸出問題,本文通過代碼講解的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11
  • SpringBoot?快速實現(xiàn)分庫分表的2種方式

    SpringBoot?快速實現(xiàn)分庫分表的2種方式

    本文將為您介紹?ShardingSphere?的一些基礎特性和架構(gòu)組成,以及在?Springboot?環(huán)境下通過JAVA編碼和Yml配置兩種方式快速實現(xiàn)分庫分表功能,感興趣的朋友跟隨小編一起看看吧
    2023-06-06

最新評論