在多线程Tomcat服务器中访问全局变量

时间:2010-05-03 09:07:04

标签: java linux multithreading tomcat openjdk

编辑:我已经发现单例的构造函数被多次调用,因此看起来这些类被单独的类加载器多次加载。如何在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机器(带有OpenJDK 1.6.0-b09的CentOS 5.4)上运行时,我添加一个映射并打印出KeyMapper使用的HashMap的大小,以验证添加的映射(即验证大小= 1)。然后我尝试用另一个请求检索映射,并且我一直变为null,当我检查HashMap的大小时它是0.我确信映射不会被意外删除,因为我已经注释掉所有要删除的调用(我不使用clear或任何其他mutators,只是获取和放置)。

请求通过Tomcat 6.24(配置为使用至少4个线程的200个线程)并且我将-Xnoclassgc传递给jvm以确保该类不会无意中收集垃圾(jvm也在-server中运行)模式)。我还为KeyMapper添加了一个finalize方法,以便在收集垃圾时验证它是否被垃圾收集。

我在我的智慧结束时,我无法弄清楚为什么一分钟HashMap中的条目存在而下一条不是:(

5 个答案:

答案 0 :(得分:5)

另一个猜测:这两个请求是否可能由您的网络应用程序的不同副本提供?每个都在它自己的ClassLoader中,因此具有不同的单身副本。

答案 1 :(得分:1)

您是否尝试删除外部检查

if(mapper == null)
{

因此总是点击同步点,它是微妙的东西,但可能你正在达到双重检查的锁定习语问题。描述here和许多其他文章。

必须承认我以前从未见过这个问题实际上咬人,但这听起来确实如此。

答案 2 :(得分:1)

使用这个解决方案,JVM保证它只有一个映射器,并且它在使用前已初始化。

public enum KeyMapperFactory {

    ;

    private static KeyMapper mapper = new LocalMemoryMapper();  

    public static KeyMapper getMapper() {
        return mapper;
    }
}

答案 3 :(得分:1)

这可能不是您的问题的原因,但您正在使用错误的双重检查锁定。见这个,

http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java

答案 4 :(得分:0)

我发现了一个相当差的修复方法。我将我的代码导出为JAR并将其放在$ TOMCAT / lib中并且有效。这显然是一个类加载器问题。

编辑:找出解决方案

好的,我终于找到了问题。

我通过添加到server.xml并将路径设置为“”使我的应用程序成为服务器的默认应用程序。但是,当我通过网址http://localhost/somepage.jsp访问某些内容时,以及其他内容的网址http://localhost/appname/anotherpage.jsp

我将所有网址更改为使用http://localhost/而不是http://localhost/appname后问题得到解决。