想法是创建一个工厂类,它根据'type'返回不同的单例实例。 [Multiton模式]。此外,应该懒惰地创建单例实例。
以下代码线程是否安全?使用ConcurrentHashMap使其更简单,但我想尝试使用HashMap。
public class Multiton {
private HashMap<String, Interface> interfaceMap;
private static class Holder {
public static final Multiton INSTANCE = new Multiton();
}
public static Multiton getInstance() {
return Holder.INSTANCE;
}
private Multiton(){
interfaceMap = new HashMap<String, Interface>();
}
public Interface getInterface(String key){
Interface value = interfaceMap.get(key);
if(null == value){
synchronized(interfaceMap){
// double check locking
if(interfaceMap.get(key) == null){
switch(key){
case TypeA : // initialize Type A interface here and put it to map
value = new TypeA();
interfaceMap.put(key, value);
break;
case TypeB : // initialize Type B interface here and put it to map
value = new TypeB();
interfaceMap.put(key, value);
break;
}
}
}
}
return interfaceMap.get(key);
}
}
答案 0 :(得分:0)
Double checked locking is (in general) not thread safe。特别是,仅在写入映射时进行同步是不够的,因为这不会阻止读取器线程访问写入器线程当前正在修改的状态。
如果您不能使用ConcurrentHashMap(例如,因为您必须确保创建单个TypeA,而不仅仅是所有客户端都使用了一个TypeA),以下内容应该可以正常工作并且相当便宜。特别是,一旦构造了惰性对象,它就会无锁。
abstract class Lazy<T> {
private volatile T instance;
abstract T create();
void get() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = create();
}
}
}
return instance;
}
}
class Multiton {
private final Map<String, Lazy<?>> map = new HashMap<>();
Multiton() {
map.put("A", new Lazy<A> {
A create() {
return new A();
}
}
map.put("B", new Lazy<B> {
B create() {
return new B();
}
}
// and so on for the other types
}
}
对于生产质量,您可能需要考虑对工厂方法使用lamdba表达式,并为映射键入安全键(例如所请求接口的类对象)。