编辑:我发现单例的构造函数被多次调用,所以看起来这些类被单独的类加载器多次加载。如何在 Tomcat 中创建全局单例?我一直在谷歌搜索,但到目前为止没有运气。
我有一个像这样构造的单例对象:
private static volatile KeyMapper mapper = null;
public static KeyMapper getMapper()
{
if(mapper == null)
{
synchronized(Utils.class)
{
if(mapper == null)
{
mapper = new LocalMemoryMapper();
}
}
}
return mapper;
}
KeyMapper 类基本上是 HashMap 的同步包装器,只有两个功能,一个用于添加映射,一个用于删除映射。在我的 32 位 Windows 机器上运行 Tomcat 6.24 时,一切正常。但是,当在 64 位 Linux 机器(CentOS 5.4 和 OpenJDK 1.6.0-b09)上运行时,我添加了一个映射并打印出 KeyMapper 使用的 HashMap 的大小,以验证是否添加了映射(即验证大小 = 1)。然后我尝试用另一个请求检索映射,但我一直为空,当我检查 HashMap 的大小时,它为 0。我确信映射不会被意外删除,因为我已经注释掉了所有删除调用(而且我不使用 clear 或任何其他变异器,只是 get 和 put)。
这些请求通过 Tomcat 6.24(配置为使用至少 4 个线程的 200 个线程),我将 -Xnoclassgc 传递给 jvm 以确保该类不会无意中收集垃圾(jvm 也在 -server 模式下运行)。我还向 KeyMapper 添加了一个 finalize 方法,以便在它被垃圾收集时打印到 stderr,以验证它没有被垃圾收集。
我束手无策,我无法弄清楚为什么一分钟 HashMap 中的条目在那里,而下一个它不是:(