3

由于存在双重检查锁定问题,因此我们必须使用同步来保证对以下方法(org.apache.struts.util.MessageResources 类)的并发访问:

惰性实例化

public synchronized static MessageResources getMessageResources(String config) {

    if (defaultFactory == null) {
        defaultFactory = MessageResourcesFactory.createFactory();
    }

    return defaultFactory.createResources(config);
}

为什么不使用:

渴望实例化

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 的并发访问,至少在我的情况下,它可能会被调用很多次。

不使用同步的含义在这里:

http://en.wikipedia.org/wiki/Double-checked_locking

4

4 回答 4

1

MessageResourcesFactory线程安全吗?该synchronized方法保护字段的设置和createResources方法调用。如果它是线程安全的,则可以移动锁定以覆盖仅设置字段并将方法调用留在临界区之外。

于 2009-08-01T21:36:39.917 回答
0

现代 JVM 上的同步方法所产生的开销非常小,以至于变得微不足道。随后对同步的惰性初始化工厂方法的调用将与对非同步的急切初始化方法的调用几乎一样快。

在代码方面,lazy-init 方法比使用静态初始化块更简单且更容易理解(在我看来)。此外,当静态 init 块失败时,很难弄清楚在哪里以及为什么会失败。

于 2009-07-27T09:46:35.400 回答
0

除非有任何原因MessageResourceFactory无法尽早初始化(例如,某些 Servlet 资源需要首先初始化),否则我认为我更喜欢您的解决方案。我猜 Struts 团队没有理由懒惰地加载工厂,除非那是从事此工作的特定开发人员习惯做的事情(即使没有必要,人们也倾向于懒惰地加载单例)。

您是否尝试过提交错误报告并提出解决方案?

于 2009-07-27T10:13:24.473 回答
0

我认为这是 Struts 确保它在多线程模式下正常工作的一种方式,无论覆盖 org.apache.struts.util.MessageResources 的人是否将 createResources(String configuration) 定义为同步或不同步。

于 2009-08-04T15:49:01.760 回答