如何使工厂线程安全?



我有一个下面的工厂,它将从多个线程调用。我想知道它是否线程安全。

public class ClientFactory {
private Map<TypeName, Provider> holder = new HashMap<>();
private static class Holder {
private static final ClientFactory INSTANCE = new ClientFactory();
}
public static ClientFactory getInstance() {
return Holder.INSTANCE;
}
private ClientFactory() {
holder.put(TypeName.typeA, new DataProvider());
holder.put(TypeName.typeB, new ProcessProvider());
}
public IProcess createNewType(TypeName typeName) {
Provider provider = holder.get(typeName);
if (provider == null) {
throw new IllegalArgumentException("invalid typeName is passed");
}
IProcess process = new ProcessImpl(typeName.name(), provider);
return process;
}
}

在我上面的工厂中createNewType方法将从多个线程调用。我想让它线程安全。线程安全吗?一旦我的HashMap填充到ClientFactory构造函数中,我就不会修改它。所以我相信它是线程安全的,因为对该HashMapget()的调用将是线程安全的。

如果它不是线程安全的,那么我怎样才能以最有效的方式使其线程安全?

简短的回答:你应该声明holderfinal。那么,所谓的共享HashaMap的发布是安全的。发布后,所有线程都可以看到它,并且由于映射的内容不会更改,因此它的行为应该像不可变的映射一样,因此是线程安全的。使地图不可修改的另一个建议也是一个很好的建议。

一些善意的咆哮:尽管您似乎担心工厂的线程安全性,但您应该解决其他一些与线程无关的问题(首先)。

没有必要
  1. 以如此复杂的方式使用持有人模式。例如,内部类需要什么来保存您立即构造的实例?

  2. holder重命名为更有意义的名称,例如typeToProvidersMap.是的,它更冗长,但使代码(更多)可读。

  3. 这是Client的工厂还是Provider的工厂?如果是后者,请相应地重命名类。此外,将createNewType()重命名为createNewProvider(),因为创建新提供程序似乎是该方法执行的操作。

即使这是示例代码,它仍然可以是示例

。通过1),我的意思是以下更好开始:

public class ClientFactory {
private final Map<TypeName, Provider> typeToProvider = new HashMap<>();
// constructing the singleton since the construction needn't be lazy
private static final ClientFactory INSTANCE = new ClientFactory();
public static ClientFactory getInstance() {
return INSTANCE;
}
// rest is omitted for brevity
}

当需要延迟初始化并考虑特定目的时,将使用 Holder 模式。

如果你的HashMap没有被修改,那么工厂类是线程安全的。尽管在映射中使用对象时可能会开始出现问题(因为它们不是线程安全的,即使 Map 实现是线程安全的)。

因此,请确保提供程序实现是线程安全的,或者在访问时锁定整个提供程序实例(这可能不是最佳解决方案)。

最新更新