我有一個單一實現的公共接口。接口定義了可以拋出檢查異常的初始化方法。單體對象的工廠:這個代碼是線程安全的嗎?
我需要一個工廠,它會按需要返回緩存的單例實現,並想知道下面的方法是否是線程安全的?
UPDATE1:請不要提出任何第三部分庫,因爲這將需要獲得法律間隙由於可能的許可問題:-)
UPDATE2:此代碼將很有可能在使用EJB環境,所以最好不要產生額外的線程或使用類似的東西。
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;
}
}
我對線條(1)和(2)不完全確定。我知道被引用的對象在AtomicReference
中被聲明爲易失性字段,因此在第(1)行所做的更改應該立即在第(2)行中可見 - 但仍然存在一些疑問... ...
除此之外 - 我認爲使用ConcurrentHashMap
解決了將新密鑰放入緩存的原子性。
你們看到這種方法的任何擔憂?謝謝!
PS:我知道靜態holder類成語 - 我不使用它由於ExceptionInInitializerError
(其中單實例化過程中引發的任何異常被包裝成)和隨後的NoClassDefFoundError
這是不是我要趕。相反,我想利用專用檢查異常的優勢,通過捕獲並優雅地處理它,而不是解析EIIR或NCDFE的堆棧跟蹤。
謝謝!在我的情況下,第三方lib不是一個選項... – anenvyguest