首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >下面的实用工具类线程安全吗?

下面的实用工具类线程安全吗?
EN

Stack Overflow用户
提问于 2009-11-11 19:51:49
回答 2查看 2.3K关注 0票数 3

首先,让我们看一下实用程序类(大多数javadoc已经移除到简单的示例中):

代码语言:javascript
复制
public class ApplicationContextUtils {

    /**
     * The application context; care should be taken to ensure that 1) this
     * variable is assigned exactly once (in the
     * {@link #setContext(ApplicationContext)} method, 2) the context is never
     * reassigned to {@code null}, 3) access to the field is thread-safe (no race
     * conditions can occur)
     */
    private static ApplicationContext context = null;

    public static ApplicationContext getContext() {

    if (!isInitialized()) {
        throw new IllegalStateException(
            "Context not initialized yet! (Has the "
                + "ApplicationContextProviderBean definition been configured "
                + "properly and has the web application finished "
                + "loading before you invoked this method?)");
    }

    return context;
    }

    public static boolean isInitialized() {
    return context == null;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(final String name, final Class<T> requiredType) {
    if (requiredType == null) {
        throw new IllegalArgumentException("requiredType is null");
    }
    return (T) getContext().getBean(name, requiredType);
    }

    static synchronized void setContext(final ApplicationContext theContext) {

    if (theContext == null) {
        throw new IllegalArgumentException("theContext is null");
    }

    if (context != null) {
        throw new IllegalStateException(
            "ApplicationContext already initialized: it cannot be done twice!");
    }

    context = theContext;
    }

    private ApplicationContextUtils() {
    throw new AssertionError(); // NON-INSTANTIABLE UTILITY CLASS
    }
}

最后,下面的实际上调用了'setContext‘方法:

代码语言:javascript
复制
public final class ApplicationContextProviderBean implements
    ApplicationContextAware {

    public void setApplicationContext(
        final ApplicationContext applicationContext) throws BeansException {
    ApplicationContextUtils.setContext(applicationContext);
    }
}

在应用程序启动后,Spring将调用一次setApplicationContext方法。假设nincompoop以前没有调用ApplicationContextUtils.setContext(),那么应该锁定对实用程序类中上下文的引用,从而允许对getContext()的调用成功(这意味着isInitialized()返回true)。

我只想知道这个类是否违反了任何良好编码实践的原则,特别是在线程安全方面(但其他发现的愚蠢之处是受欢迎的)。

谢谢你帮助我成为一个更好的程序员,StackOverflow!

你好,莱斯

P.S.我没有深入说明为什么我需要这个实用程序类--让我确实有一个合法的需求,从应用程序中的任何地方(当然,在spring上下文加载之后)访问它。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-11-11 19:56:44

不是的。这不是线的安全。

写入context类变量对于通过getContext()读取该变量的线程不一定是可见的。

至少,声明contextvolatile。理想情况下,通过这样的调用将context重新定义为AtomicReference

代码语言:javascript
复制
if(!context.compareAndSet(null, theContext))
  throw new IllegalStateException("The context is already set.");

下面是一个更完整的例子:

代码语言:javascript
复制
public class ApplicationContextUtils {

  private static final AtomicReference<ApplicationContext> context = 
    new AtomicReference<ApplicationContext>();

  public static ApplicationContext getContext() {
    ApplicationContext ctx = context.get();
    if (ctx == null)
      throw new IllegalStateException();
    return ctx;
  }

  public static boolean isInitialized() {
    return context.get() == null;
  }

  static void setContext(final ApplicationContext ctx) {
    if (ctx == null) 
      throw new IllegalArgumentException();
    if (!context.compareAndSet(null, ctx))
      throw new IllegalStateException();
  }

  public static <T> T getBean(final String name, final Class<T> type) {
    if (type == null) 
      throw new IllegalArgumentException();
    return type.cast(getContext().getBean(name, type));
  }

  private ApplicationContextUtils() {
    throw new AssertionError();
  }

}

注意,除了线程安全之外,这还提供了类型安全性,利用了传递到getBean()方法的getBean()实例。

我不确定您打算如何使用isInitialized()方法;对我来说,它似乎不太有用,因为一旦您调用它,条件就会改变,而且您也没有一个很好的方法来通知它。

票数 9
EN

Stack Overflow用户

发布于 2009-11-29 20:00:49

Spring已经有一个名为ContextSingletonBeanFactoryLocator的类,它将静态访问连接到ApplicationContext。至少,使用这个类可能会为您省去担心自定义方法是否线程安全的麻烦。

不过,一开始使用这个类有点让人费解,因为存在一些间接的情况。有关此调用如何工作的更多信息,您可以查看这篇博客文章

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1717625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档