【问题标题】:Flood of EHCache threads spawned on startup启动时产生大量 EHCache 线程
【发布时间】:2011-04-07 19:40:03
【问题描述】:

更新:仍然感到困惑。我认为唯一的可能性是在生成线程后在 init() 方法中引发异常但未记录该异常。我捕获了 create() 方法中抛出的所有异常并将它们记录到警告日志中。任何人都有关于为什么 Log4J 无法打印我的日志消息的理论?日志记录级别设置为 WARN。

我正在 JBoss 上使用 EHCache 运行 Spring 3.0 应用程序。有时当我启动应用服务器时,JVM 会在 20 或 30 秒内完全关闭。我将它设置为每 5 秒进行一次线程转储,并发现在大约 15 秒后,转储开始在同一个线程中呈指数级增长:

"net.sf.ehcache.CacheManager@7d73124b" daemon prio=10 tid=0x00002aac1426a000 nid=0x2300 in Object.wait() [0x00002aac0d886000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00002aaaf5c556e0> (a java.util.TaskQueue)
    at java.lang.Object.wait(Object.java:485)
    at java.util.TimerThread.mainLoop(Timer.java:483)
    - locked <0x00002aaaf5c556e0> (a java.util.TaskQueue)
    at java.util.TimerThread.run(Timer.java:462)

到系统关闭时,大约有 10,000 个线程看起来与此完全相同,只是内存地址发生了变化。

我做了一些研究,发现 EHCache 的缓存管理器在 init() 方法中生成了这个线程,该方法由它的每个构造函数调用。缓存管理器应该是一个可以通过 create() 方法访问的单例:

public static CacheManager create() throws CacheException {
    if (singleton != null) {
        return singleton;
    }
    synchronized (CacheManager.class) {
        if (singleton == null) {
            LOG.debug("Creating new CacheManager with default config");
            singleton = new CacheManager();
        } else {
            LOG.debug("Attempting to create an existing singleton. Existing singleton returned.");
        }
        return singleton;
    }
}

每 5 秒进行一次线程转储,当这些线程成倍增加时,我可以看到堆栈跟踪。该同步块中始终存在一个线程,该线程已进入构造函数并将生成一个线程。然后总是有几个线程等待进入同步块。

据我所知,在同步块内对 singleton 进行空检查应该可以防止多个条目进入构造函数,但不知何故,每个线程似乎都在寻找 singleton em> 为空。我将所有异常记录到警告日志中,所以我认为如果在构造函数中创建线程后抛出异常,我会在日志中看到它。我没有看到任何警告,但我证实这会导致这种行为。

有没有人知道如何使多个线程进入该构造函数? java是否会缓存空检查,因为它刚刚对上一行的相同字段进行了空检查?

【问题讨论】:

  • 奥卡姆剃刀可能会对你有所帮助

标签: java concurrency ehcache


【解决方案1】:

查看线程转储,似乎真正的问题可能是定时器运行异常,它不断产生访问缓存管理器的线程。我想我会先检查您的代码,以验证您没有触发等待时间为 0 的计时器(可能是时间偏移计算错误的结果)。

【讨论】:

  • 即使有一个定时器不断地访问缓存管理器,它也被实现为一个单例。您应该可以根据需要多次访问它。
【解决方案2】:

如果这是由缓存管理器的 init 产生的线程,那么它们可能是在 ehcache 站点上监视版本更新的线程(尽管我不能确定)。可以使用 Terracotta 的运行时属性(我不记得它的名称)或缓存配置设置(一些 XML 属性或 Spring setter,取决于缓存配置的定义方式)来抑制这些检查。

【讨论】:

  • 谢谢,但我已经禁用了更新检查器。这是检查更新的线程,但它没有指出创建了多少更新。
  • 我不知道为什么这么多(从来没有过)。但是,如果这是更新检查线程,那么我认为(再次,不确定)您可以阻止它的“创建”(我感觉我在回答中提到的这两个设置之一已应用于较晚线程创建后)。
【解决方案3】:

试图创建一个现有的单例。返回现有的单例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    • 2015-08-22
    • 2013-12-28
    • 2021-08-11
    • 2020-03-08
    • 2016-12-04
    • 2022-09-29
    相关资源
    最近更新 更多