Ho un'interfaccia comune per un numero di implementazioni singleton. L'interfaccia definisce il metodo di inizializzazione che può generare un'eccezione controllata.Fabbrica di oggetti singleton: questo codice è sicuro per il thread?
Ho bisogno di un factory che restituisca le implementazioni singleton memorizzate nella cache su richiesta, e mi chiedo se il seguente approccio sia thread-safe?
Update1: Si prega di non qualsiasi proposta di 3a in parte le biblioteche, in quanto richiede per ottenere l'autorizzazione legale a causa di possibili problemi di licenza :-)
UPDATE2: questo codice sarà probabilmente da utilizzare in Ambiente EJB, quindi è preferibile non generare thread aggiuntivi o usare cose del genere.
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;
}
}
Non sono del tutto sicuro di linee (1) e (2). So che l'oggetto di riferimento è dichiarato come campo volatile in AtomicReference
, e quindi le modifiche apportate alla riga (1) dovrebbero diventare immediatamente visibili alla riga (2) - ma hanno ancora qualche dubbio ...
Oltre a questo - penso l'uso di ConcurrentHashMap
indirizza l'atomicità di inserire una nuova chiave in una cache.
Ragazzi, vedete qualche preoccupazione con questo approccio? Grazie!
PS: so di statica idioma di classe titolare - e io non lo uso a causa di ExceptionInInitializerError
(che qualsiasi eccezione generata durante la creazione di un'istanza Singleton è avvolto in) e la successiva NoClassDefFoundError
che non sono qualcosa che voglio per la cattura . Invece, vorrei sfruttare il vantaggio dell'eccezione verificata dedicata catturandola e gestendola con garbo piuttosto che analizzare la traccia stack di EIIR o NCDFE.
Grazie! Liberia di terze parti non è un'opzione nel mio caso ... – anenvyguest