Tengo una interfaz común para varias implementaciones de singleton. La interfaz define el método de inicialización que puede arrojar una excepción marcada.Fábrica de objetos singleton: ¿este código es seguro para subprocesos?
Necesito una fábrica que devolverá las implementaciones de singleton en caché bajo demanda, y me pregunto si el siguiente enfoque es seguro para subprocesos
Update1: Por favor, no sugieren ningún parcialmente bibliotecas 3ª, ya que esto requerirá para obtener la autorización legal debido a posibles problemas de licencia :-)
Update2: este código es probable que se utilizará en Entorno EJB, por lo que es preferible no generar hilos adicionales o usar cosas como esa.
interface Singleton
{
void init() throws SingletonException;
}
public class SingletonFactory
{
private static ConcurrentMap<String, AtomicReference<? extends Singleton>> CACHE =
new ConcurrentHashMap<String, AtomicReference<? extends Singleton>>();
public static <T extends Singleton> T getSingletonInstance(Class<T> clazz)
throws SingletonException
{
String key = clazz.getName();
if (CACHE.containsKey(key))
{
return readEventually(key);
}
AtomicReference<T> ref = new AtomicReference<T>(null);
if (CACHE.putIfAbsent(key, ref) == null)
{
try
{
T instance = clazz.newInstance();
instance.init();
ref.set(instance); // ----- (1) -----
return instance;
}
catch (Exception e)
{
throw new SingletonException(e);
}
}
return readEventually(key);
}
@SuppressWarnings("unchecked")
private static <T extends Singleton> T readEventually(String key)
{
T instance = null;
AtomicReference<T> ref = (AtomicReference<T>) CACHE.get(key);
do
{
instance = ref.get(); // ----- (2) -----
}
while (instance == null);
return instance;
}
}
No estoy del todo seguro acerca de las líneas (1) y (2). Sé que el objeto referenciado se declara como campo volátil en AtomicReference
y, por lo tanto, los cambios realizados en la línea (1) deberían ser inmediatamente visibles en la línea (2), pero todavía tengo algunas dudas ...
Aparte de eso, creo El uso de ConcurrentHashMap
aborda la atomicidad de poner una nueva clave en un caché.
¿Vieron alguna preocupación con este enfoque? ¡Gracias!
PS: que sé de lenguaje de clase estática titular - y yo no lo uso debido a ExceptionInInitializerError
(que cualquier excepción lanzada durante la instanciación Singleton se envuelve en) y la posterior NoClassDefFoundError
que no son algo que quiero coger . En cambio, me gustaría aprovechar la ventaja de la excepción comprobada dedicada al capturarlo y manejarlo con elegancia en lugar de analizar el rastro de la pila de EIIR o NCDFE.
Gracias! La lib de terceros no es una opción en mi caso ... – anenvyguest