【问题标题】:Threading issue with google guice and springgoogle guice和spring的线程问题
【发布时间】:2014-05-06 18:13:30
【问题描述】:

我需要将现有的 spring 应用程序与自定义的 elasticsearch 河集成,ES 河使用 Google Guice 管理它们的依赖关系并在它们自己的线程集中运行。

我创建了一个简单的类,它返回对 spring 上下文的静态引用,并配置了一个从 spring 上下文返回对象的 Guice 模块。为了确保 guice 线程和 spring 线程之间的正确同步,我使用了在上下文完全初始化后释放的CountDownLatch。这是一些代码

public class GuiceSpringIntegrator implements ApplicationListener<ContextRefreshedEvent> {

    private static ApplicationContext context;

    private static final CountDownLatch contextLatch = new CountDownLatch(1);

    @Override public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            // check some stuff in context
        } finally {
            log.debug("Setting application context as static field of {}", getClass().getSimpleName());
            GuiceSpringIntegrator.context = event.getApplicationContext();
            log.info("Releasing latch for application context");
            contextLatch.countDown();
        }
    }

    public static ApplicationContext getApplicationContext() {
        if (null == context) {
            log.info("ApplicationContext not yet initialized, wait for it in thread {}", Thread.currentThread().getName());
            Uninterruptibles.awaitUninterruptibly(contextLatch); <-- !!! SPRING INITIALIZATION CODE HANGS HERE
            log.debug("Returning application context since now context is initialized");
            Preconditions.checkState(context != null, "ApplicationContext should have been initialized properly");
        }
        return context;
    }
}

这是使用上述类的guice模块

/**
 * Guice module configuration
 */
public class ElasticSearchModule extends AbstractModule {

    @Override
    protected void configure() {}

    @Provides @Singleton TaskScheduler getSchedulerInstance() {
        return GuiceSpringIntegrator.getApplicationContext().getBean(TaskScheduler.class);
    }
    // and so on...
}

但是,当我启动应用程序(尤其是在快速服务器上)时,应用程序偶尔会挂在上面代码中标记的行。我仔细检查了导致#getApplicationContext() 方法调用的每个代码路径,它们(应该)被guice调用,所以最终应该释放闩锁并且代码应该继续。

  1. 有没有更好的方法来处理这种情况?
  2. 有没有办法检查我是否在 spring 初始化代码中,比如isEventDispatchThread for swing?如果我以某种方式从 Spring 初始化代码中调用 #getApplicationContext,我想使用该代码进行跟踪?
  3. 为什么在上下文初始化实际完成之前似乎调用了#onApplicationEvent?
  4. 有关如何调试此问题的任何提示?我正在阅读有关在实时服务器上进行线程转储的信息,对吗?

【问题讨论】:

  • 如果您可以重现死锁,分析堆栈跟踪(例如,kill -3)确实会有所帮助。顺便说一句,你看到你的日志条目了吗?你确定调用了 onApplicationEvent 吗?
  • @PhilippClaßen 我将尝试使用kill -3 我现在正在寻找有关此的更多信息。发生死锁的时候是因为onApplicationEvent没有被调用,所以我的想法是一些配置好的spring bean间接调用getApplicationContext整个事情挂了。

标签: java multithreading spring deadlock guice


【解决方案1】:

除了第 4 点之外,这并不能真正回答您的问题,但我想编写代码,所以我将其作为答案而不是评论。

我会尝试改变这个:

Uninterruptibles.awaitUninterruptibly(contextLatch); <-- !!! SPRING INITIALIZATION CODE HANGS HERE

到这里:

boolean awaitResult = Uninterruptibles.awaitUninterruptibly(contextLatch, 2, TimeUnit.MINUTES);
if(awaitResult) {
    throw new IllegalStateException("Unable to load Spring Context");
}

然后您可以在某处捕获该异常并将其堆栈跟踪写入日志;这不会解决您的问题,但它可能会让您更清楚地了解死锁的位置?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    相关资源
    最近更新 更多