谷歌guice和春天的线程问题

时间:2014-05-06 18:13:30

标签: java multithreading spring deadlock guice

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

我创建了一个简单的类,它返回对spring上下文的静态引用,并配置了一个Guice模块,该模块从spring上下文返回对象。为了确保在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. 有没有办法检查我是否在弹簧初始化代码中,如isEventDispatchThread for swing?我想使用该代码来追踪我是否以某种方式从弹簧初始化代码中调用#getApplicationContext
  3. 为什么在实际完成上下文初始化之前似乎会调用#onApplicationEvent
  4. 有关如何调试此问题的任何提示?我正在读关于在实时服务器上进行线程转储,是吗?

1 个答案:

答案 0 :(得分:0)

除了第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");
}

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