This is a variation of the perpertual "lengthy-if or switch" dilemma...
Consider a multithreaded application using a static method that contains a long (over a dozen conditions) if
statement, which checks the type of an object and returns a value accordingly, i.e. something like
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;
}
}
Obviously a switch statement is not directly applicable here, so a common pattern is to have an enum
and call its valueOf()
, i.e. do something like
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;
}
}
So, checkType()
could be re-written as
public static String checkType(Class<?> type)
{
return Strings.valueOf(getActualTypeName(type.getClass().getName())).value();
}
with appropriate checks for null
values added in production code and some String processing for non-primitive types, inside the getActualTypeName()
method, to retrieve the actual type name from strings like "class java.lang.Long"
(for primitives, the getName()
method returns the expected string, e.g. "long"
).
However, if valueOf()
is not thread-safe, this will not work in a concurrent environment. The same applies to using a (normal) Map
object and probably these two alternatives are variants of the same pattern, since enum.valueOf()
is apparently based on
Enum.valueOf(Class<T> enumType, String name)
which calls
enumType.enumConstantDirectory().get(name);
in the Class.java
class.
The enumConstantDirectory()
method, every time invoked, returns a new HashMap
, created from a copy of the values()
array.
Would that be thread safe?
I can't find any reasons why
enum.valueOf(String)
would not be thread safe:valueOf
does its jobWhat makes you think that
enum.valueOf()
is not thread safe?EDIT
valueOf calls:
where
enumType
is your enum class.enumConstantDirectory() uses this pattern:
where
enumConstantDirectory
is a volatile variable:Imagine a thread arriving concurrently in that method:
enumConstantDirectory
is null (there is no visibility issue here because it is volatile), it will construct the map and assign it to that variable. Because of the volatile guarantees, all other threads, from that point in time, will see the map fully constructed.enumConstantDirectory
, it will recreate the map and safely publish it againThe worst case scenario here is that 2 threads could potentially be using 2 different maps (different instances) but their content will be the same so it would not cause any issues.
Bottom line: there is no way that a thread could see a map which is half constructed, because the map construction is done on a local variable, which is assigned to the volatile variable after it has been populated.