我在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秒进行一次线程转储,我可以在这些线程相乘时看到堆栈跟踪。同步块中总有一个线程已经使它成为构造函数并将生成一个线程。然后总有几个线程等待进入同步块。
据我所知,对synchronized块中的 singleton 进行空检查应该会阻止多个条目进入构造函数,但不知何故,每个线程似乎都在找 singleton 为null。我记录了警告日志的所有异常,所以我想如果在构造函数中创建线程后抛出异常,我会在日志中看到它。我没有看到任何警告,但我确认这会导致这种行为。
有没有人知道多个线程如何才能使它成为该构造函数? java会缓存null检查,因为它只检查了前一行上的相同字段吗?
答案 0 :(得分:0)
查看线程转储,看起来真正的问题可能是计时器运行错误,它不断产生访问缓存管理器的线程。我想我首先检查一下你的代码,以确认你没有使用0等待时间来触发计时器(可能是计算错误时间偏差的结果)。
答案 1 :(得分:0)
如果这是由缓存管理器的init生成的线程,那么他们可能是在ehcache站点上观察版本更新的线程(虽然我不能确定)。可以使用Terracotta的运行时属性(我不记得它的名称)或缓存配置设置(某些XML属性或Spring setter,取决于如何定义缓存配置)来抑制这些检查。
答案 2 :(得分:-2)
尝试创建现有的单身人士。现有的单身人士返回。