ОБНОВЛЕНИЕ: Все еще озадачен. Я думаю, что единственная возможность - это исключение, вызванное внутри метода init() после создания потока, но исключение не регистрируется. Я перехватываю все исключения, возникающие в методе create(), и записываю их в журнал предупреждений. У кого-нибудь есть теория о том, почему Log4J не сможет распечатать мои сообщения журнала? Уровень ведения журнала установлен на ПРЕДУПРЕЖДЕНИЕ.
Я запускаю приложение Spring 3.0, используя EHCache на JBoss. Иногда, когда я запускаю сервер приложений, 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(), который вызывается каждым из его конструкторов. Cache Manager должен быть синглтоном, доступ к которому осуществляется через метод 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 секунд, я могу видеть трассировку стека по мере умножения этих потоков. Внутри этого блока синхронизации всегда есть один поток, который добрался до конструктора и порождает поток. Затем всегда есть несколько потоков, ожидающих попадания в синхронизированный блок.
Насколько я могу судить, эта проверка null для singleton внутри синхронизированного блока должна предотвращать более одного входа в конструктор, но почему-то кажется, что каждый поток находит singleton для быть нулевым. Я регистрирую все исключения в журнале предупреждений, поэтому я думаю, что если бы исключение возникло после создания потока в конструкторе, я бы увидел его в журнале. Я не вижу никаких предупреждений, но я убедился, что это может привести к такому поведению.
Есть ли у кого-нибудь другая идея, как более чем один поток может добраться до этого конструктора? Будет ли java кэшировать нулевую проверку, поскольку она только что проверила нулевое значение того же поля в предыдущей строке?