Mam wspólny interfejs dla wielu wdrożeń singleton. Interfejs definiuje metodę inicjalizacji, która może rzucić zaznaczony wyjątek.Fabryka obiektów singleton: czy ten kod jest bezpieczny dla wątków?
Potrzebuję fabryki, która na żądanie zwróci buforowane wdrożenia singleton i zastanawiam się, czy następujące podejście jest bezpieczne dla wątków?
UPDATE1: Proszę nie sugerować żadnych 3rd częściowo bibliotek, jak będzie to wymagało, aby uzyskać luz prawnej z powodu możliwych problemów licencyjnych :-)
Update2: kod ten może być stosowany w Środowisko EJB, więc lepiej jest nie spawnować dodatkowych wątków lub używać takich rzeczy.
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;
}
}
Nie jestem całkowicie pewien linii (1) i (2). Wiem, że obiekt odniesienia jest zadeklarowany jako zmienne pole w AtomicReference
, a zatem zmiany wprowadzone w linii (1) powinny być natychmiast widoczne w linii (2) - ale nadal mają pewne wątpliwości ...
Poza tym - myślę użycie adresu ConcurrentHashMap
dotyczy atomowości umieszczania nowego klucza w pamięci podręcznej.
Czy widzicie jakieś obawy związane z tym podejściem? Dzięki!
PS: wiem o statycznej klasy uchwyt idiomu - i nie używać go z powodu ExceptionInInitializerError
(co każdy wyjątek rzucony podczas singleton instancji jest owinięty w późniejszym NoClassDefFoundError
) i które nie są czymś, chcę złapać . Zamiast tego chciałbym wykorzystać zalety dedykowanego sprawdzanego wyjątku, łapiąc go i traktując go z gracją, zamiast analizować ślad stosu EIIR lub NCDFE.
Dzięki! Niezależna biblioteka nie jest opcją w moim przypadku ... – anenvyguest