这是一个永久的变化“冗长-如果或切换”的困境.
考虑使用静态方法的多线程应用程序,该方法包含一个长(十几个条件) 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;
}
}
显然,开关语句在这里并不直接适用,因此常见的模式是拥有一个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()
方法中对非原始类型进行一些字符串处理,以便从"class java.lang.Long"
这样的字符串中检索实际的类型名称(对于原语,getName()
方法返回预期的字符串,例如“long"
”)。
但是,如果valueOf()
不是线程安全的,那么在并发环境中这是行不通的。这同样适用于使用(正常) Map
对象,这两个替代方案可能是相同模式的变体,因为enum.valueOf()
显然是基于
Enum.valueOf(Class<T> enumType, String name)
打电话
enumType.enumConstantDirectory().get(name);
在Class.java
类中。
每次调用enumConstantDirectory()
方法时,都会返回从values()
数组的副本创建的新HashMap
。
那是线安全吗?
发布于 2012-08-16 04:37:33
我找不到为什么enum.valueOf(String)
不安全于线程的任何原因:
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
的空值,它将重新创建映射并再次安全地发布它。最坏的情况是,两个线程可能使用两个不同的映射(不同的实例),但是它们的内容是相同的,因此不会引起任何问题。
底线:线程不可能看到一半构造的映射,因为映射构造是在局部变量上完成的,该局部变量在填充后分配给易失性变量。
发布于 2012-08-16 04:38:20
没有理由认为Enum.valueOf()
不是线程安全的。它不会变异任何东西,它只访问实际enum
类中的状态,这实际上是最终的状态。
如果这个方法是非线程安全的,我认为javadocs中会有这样的内容。
发布于 2012-08-16 04:47:27
也许我错了,但这里似乎有一个微妙的问题:
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);
enumConstantDirectory()
检查enumConstantDirectory == null
,但它不是同步的,以便创建HashMap
。也许副作用并不重要(我不知道Class
存储了什么信息),但无论如何,只要应用程序代码中没有共享enumType
,它肯定是安全的。
https://stackoverflow.com/questions/11987224
复制相似问题