由于存在Double-checked锁定问题,因此我们必须使用同步来保证对以下方法的并发访问(org.apache.struts.util.MessageResources类):
懒惰的实施
public synchronized static MessageResources getMessageResources(String config) {
if (defaultFactory == null) {
defaultFactory = MessageResourcesFactory.createFactory();
}
return defaultFactory.createResources(config);
}
为什么不使用:
EAGER INSTANTIATION
static {
// Construct a new instance of the specified factory class
try {
if (clazz == null)
clazz = RequestUtils.applicationClass(factoryClass);
MessageResourcesFactory defaultFactory =
(MessageResourcesFactory) clazz.newInstance();
} catch (Exception e) {
LOG.error("MessageResourcesFactory.createFactory", e);
}
}
然后:
public static MessageResources getMessageResources(String config) {
return defaultFactory.createResources(config);
}
它允许并发访问方法getMessageResources,至少在我的情况下可能会被调用很多次。
不使用synchronized时的含义在这里:
答案 0 :(得分:1)
MessageResourcesFactory
线程安全吗? synchronized
方法可以保护字段设置和createResources
方法调用。如果它是线程安全的,则可以移动锁定以覆盖仅设置字段并将方法调用留在临界区之外。
答案 1 :(得分:0)
现代JVM上的同步方法所产生的开销非常小,以致无法实现。对调试同步的lazy-init工厂方法的后续调用将与调用非同步的eager-init方法一样快。
就代码而言,与使用静态初始化程序块相比,lazy-init方法更简单,更容易理解(在我看来)。此外,当静态初始化块失败时,弄清楚何处和原因可能会非常混乱。
答案 2 :(得分:0)
除非有任何理由MessageResourceFactory
不能在早期初始化(例如,某些Servlet资源需要先初始化),我想我更喜欢你的解决方案。我猜想Struts团队没有理由懒洋洋地加载工厂,而不是特定的开发人员习惯这样做(人们确实倾向于懒散地加载单例,即使没有必要)。
您是否尝试过提交错误报告并提出解决方案?
答案 3 :(得分:0)
我认为这是Struts确保在多线程模式下工作正常的一种方式,无论覆盖org.apache.struts.util.MessageResources的人是否将createResources(String配置)定义为已同步