[英]Thread safety of enum valueOf()
這是普通的“冗長的if或switch”困境的變體。
考慮使用包含長(超過十二個條件) if
語句的靜態方法的多線程應用程序,該語句檢查對象的類型並相應地返回值,例如
public static String checkType(Class<?> type)
{
if (type == A.class)
{
return aString;
}
else if (type == B.class)
{
return bString;
}
...
else if (type == z.class)
{
return zString;
}
}
顯然,switch語句不適用於此處,因此常見的模式是擁有一個enum
並調用其valueOf()
,即執行類似的操作
public enum Strings
{
A(aString), B(bString), ..., Z(zString)
private final String value;
private Strings(String value)
{
this.value = value;
}
public String value()
{
return this.value;
}
}
因此, checkType()
可以重寫為
public static String checkType(Class<?> type)
{
return Strings.valueOf(getActualTypeName(type.getClass().getName())).value();
}
通過對生產代碼中添加的null
值進行適當的檢查,並在getActualTypeName()
方法內對非原始類型進行一些String處理,以從諸如"class java.lang.Long"
字符串中檢索實際的類型名稱(對於基元,則為getName()
方法返回預期的字符串,例如“ long"
)。
但是,如果valueOf()
不是線程安全的,則在並發環境中將不起作用。 使用(普通) Map
對象時也是如此,這兩個選擇可能是同一模式的變體,因為enum.valueOf()
顯然基於
Enum.valueOf(Class<T> enumType, String name)
哪個電話
enumType.enumConstantDirectory().get(name);
在Class.java
類中。
每次調用enumConstantDirectory()
方法時,都會返回一個新的HashMap
,該HashMap
是從values()
數組的副本創建的。
那是線程安全的嗎?
我找不到為什么enum.valueOf(String)
不是線程安全的任何原因:
valueOf
執行其工作時不能對參數進行valueOf
是什么讓您認為enum.valueOf()
不是線程安全的?
編輯
valueOf調用:
T result = enumType.enumConstantDirectory().get(name);
其中enumType
是您的枚舉類。
enumConstantDirectory()使用以下模式:
Map<String, T> enumConstantDirectory() {
if (enumConstantDirectory == null) {
T[] universe = getEnumConstantsShared();
if (universe == null)
throw new IllegalArgumentException(
getName() + " is not an enum type");
Map<String, T> m = new HashMap<>(2 * universe.length);
for (T constant : universe)
m.put(((Enum<?>)constant).name(), constant);
enumConstantDirectory = m;
}
return enumConstantDirectory;
}
其中enumConstantDirectory
是易失性變量:
private volatile transient Map<String, T> enumConstantDirectory = null;
想象一個線程在該方法中同時到達:
enumConstantDirectory
為null(此處不存在可見性問題,因為它是易失性的),它將構造映射並將其分配給該變量。 由於存在可變保證,因此從該時間點開始,所有其他線程將看到映射已完全構建。 enumConstantDirectory
的空值,則它將重新創建地圖並再次安全地發布它 這里最壞的情況是2個線程可能使用2個不同的映射(不同的實例),但是它們的內容將相同,因此不會引起任何問題。
底線 :線程無法看到一半構造的映射,因為映射構造是在局部變量上完成的,該局部變量在填充后分配給volatile變量。
沒有理由認為Enum.valueOf()
不是線程安全的。 它不會改變任何東西,它只是訪問實際enum
類中的狀態,而狀態實際上是最終的。
如果此方法是非線程安全的,我認為會有什么東西在Javadoc中這樣說。
可能是我錯了,但似乎這里有一個微妙的問題:
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 constant " + enumType.getCanonicalName() + "." + name);
}
這是valueOf的代碼。 它使用傳入的enumType
來創建帶有常量的內部HashMap
,並且代碼未sychronized
。
這里似乎存在一個細微的問題: T result = enumType.enumConstantDirectory().get(name);
為了創建HashMap
, enumConstantDirectory()
對enumConstantDirectory == null
了檢查, enumConstantDirectory == null
同步。 也許副作用並不重要(我不知道Class
存儲什么信息),但是在任何情況下,只要在應用程序代碼中未共享enumType
它肯定是安全的
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.