亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java枚舉是怎么保證線程安全的

發布時間:2021-11-19 17:00:22 來源:億速云 閱讀:186 作者:iii 欄目:編程語言

本篇內容介紹了“java枚舉是怎么保證線程安全的”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

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

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

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

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

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關鍵字告訴我們,這個類也是不能被繼承的。當我們使用enmu來定義一個枚舉類型的時候,編譯器會自動幫我們創建一個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類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。

為什么用枚舉實現的單例是最好的方式

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

1. 枚舉寫法簡單

寫法簡單這個大家看看[轉+注]單例模式的七種寫法里面的實現就知道區別了。

public enum EasySingleton{INSTANCE;}

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

2. 枚舉自己處理序列化

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

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

在序列化的時候Java僅僅是將枚舉對象的name屬性輸出到結果中,反序列化的時候則是通過java.lang.Enum的valueOf方法來根據名字查找枚舉對象。

同時,編譯器是不允許任何對這種序列化機制的定制的,因此禁用了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); }

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

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

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

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

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

“java枚舉是怎么保證線程安全的”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

贡嘎县| 上高县| 马关县| 福建省| 郎溪县| 麻阳| 淅川县| 安国市| 城口县| 婺源县| 龙胜| 集贤县| 阳春市| 思南县| 潞城市| 锡林郭勒盟| 庄浪县| 安新县| 洛浦县| 台湾省| 当雄县| 罗平县| 潮安县| 涟源市| 友谊县| 玛沁县| 凌云县| 厦门市| 保定市| 旺苍县| 临湘市| 河津市| 廉江市| 普洱| 衡南县| 普兰店市| 资讯| 斗六市| 唐河县| 阳东县| 察雅县|