你的方法不是線程安全的:
private static Map<Class<MyClass<?>>, MyClass<?>> s_instances =
new HashMap<Class<MyClass<?>>, MyClass<?>>();
public static MyClass<?> blah(Class<MyClass<?>> clz)
throws InstantiationException, IllegalAccessException {
if (s_instances.get(clz) != null)
return s_instances.get(clz);
// here1
MyClass<?> instance = clz.newInstance();
s_instances.put(clz, instance);
// here2
return instance;
}
一旦一個線程獲得過去行標//here1
,之前第一個線程在標//here2
行,因此創造了第二個第二個線程可能進入方法同一種「單身人士」並覆蓋地圖中的第一個。
的快速解決將是在地圖上進行同步:
public static MyClass<?> blah(Class<MyClass<?>> clz)
throws InstantiationException, IllegalAccessException {
synchronized(s_instances){
if (s_instances.get(clz) != null)
return s_instances.get(clz);
// here1
MyClass<?> instance = clz.newInstance();
s_instances.put(clz, instance);
// here2
return instance;
}
}
然而,這將意味着許多線程必須等待了很多時間,最終可能殺死你的應用程序。也許你應該做的是兩個步驟的解決方案:
public static MyClass<?> blah(Class<MyClass<?>> clz)
throws InstantiationException, IllegalAccessException {
Object candidate = s_instances.get(clz);
if(clz.isInstance(candidate)){ // implicit null check
return clz.cast(candidate);
}
synchronized(s_instances){
Object candidate = s_instances.get(clz);
if(clz.isInstance(candidate)){ // gotta check a second time in a
return clz.cast(candidate); // synchronized context
}
MyClass<?> instance = clz.newInstance();
s_instances.put(clz, instance);
return instance;
}
}
而且,一個HashMap不適合併發訪問,所以您應該在Collections.synchronizedMap()
把它包:
private static Map<Class<MyClass<?>>, MyClass<?>> s_instances =
Collections.synchronizedMap(new HashMap<Class<MyClass<?>>, MyClass<?>>());
或與去改爲ConcurrentHashMap
。
在你的例子中,不太確定每種類型有不同的實例。新實例必須是「MyClass」(不是子類)的確切類型,所以你可以調用MyClass的構造函數(不需要反射)。 – artbristol