2010-05-03 68 views
2

編輯:我已經找到了單例的構造函數被多次調用,所以它看起來類正在被不同的類加載器多次加載。我如何在Tomcat中創建一個全球單身人士?我一直在使用谷歌搜索,但目前還沒有運氣。在多線程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)。然後我嘗試用另一個請求來檢索映射,並且我一直收到null,並且當我檢查HashMap的大小時它是0.我相信映射不會意外地被刪除,因爲我已經註釋掉所有要刪除的調用(並且我不使用清晰的或任何其他的增變器,只是得到並放置)。

請求正在通過Tomcat 6.24(配置爲使用至少4個線程的200個線程),並且我將-Xnoclassgc傳遞給jvm以確保類不會無意中收集垃圾(jvm也在運行 - 服務器模式)。我還爲KeyMapper添加了一個finalize方法,如果垃圾收集器確認它沒有被垃圾收集,就會打印到stderr。

我在我束手無策,我想不通,爲什麼一分鐘HashMap中的條目是存在的,接下來它不是:(

+1

我認爲你的bug是在其他地方。 – 2010-05-03 12:32:36

回答

0

我發現一個相當差的修復程序。我將我的代碼作爲JAR導出,並將其放在$ TOMCAT/lib中並且工作正常。這顯然是一個類加載器問題。

編輯:找出解決方案

好吧,我終於弄清楚了這個問題。

我已經通過添加到server.xml並將路徑設置爲「」使我的應用程序成爲服務器的默認應用程序。但是,當我通過URL http://localhost/somepage.jsp訪問它時,對於其他東西也是URL http://localhost/appname/anotherpage.jsp

一旦我更改了所有使用http://localhost/而不是http://localhost/appname的URL,問題就解決了。

1

你有沒有嘗試刪除外檢查

if(mapper == null) 
{ 

因此總是擊中同步點,這是微妙的東西,但可能你打的雙重檢查鎖定成語的問題。描述here和許多其他文章。

必須承認,我從來沒有見過這個問題實際上咬人之前,但是這聽起來確實如此。

+1

如果他不想每次都碰到同步塊,那麼在施工過程中總會有靜態塊。不是問題的答案是肯定的,但也許是解決問題的辦法。 – extraneon 2010-05-03 10:00:42

+0

啊,這正是作者提出的解決方案,就在底部。 – extraneon 2010-05-03 10:06:28

1

有了這個解決方案,JVM保證它只有一個映射器,並且它在使用之前被初始化。

public enum KeyMapperFactory { 

    ; 

    private static KeyMapper mapper = new LocalMemoryMapper(); 

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

我試過這個,我仍然遇到同樣的問題。我在KeyMapper構造函數中放置了一個打印語句,我可以驗證構造函數被調用兩次。我的代碼看起來與您發佈的內容完全相同,並且它是我創建該類實例的唯一位置。我的猜測是問題是與JVM,Tomcat或類加載器的設置有關 – jwegan 2010-05-03 16:22:17

+0

您可以嘗試在創建映射器之後添加打印語句嗎?也許它是從別的地方調用的。 如果上述問題沒有解決您的問題,我相信您的代碼正在幾個類加載器中運行。 – Espen 2010-05-03 19:22:17

5

再大膽猜一下:是否有可能在兩個請求是由您的Web應用程序的不同副本送達?每個將在其自己的ClassLoader,因此有一個單身的不同副本。

+0

我已驗證單例正在實例化兩次,當我將代碼移入$ TOMCAT_HOME/lib時,我能夠讓單例工作,因此顯然是類加載器問題。我的應用程序只是一堆JSP,我沒有在web.xml中定義任何servlet。你有什麼想法如何向我的應用程序請求使用相同的類加載器? – jwegan 2010-05-03 20:04:41

+0

看起來像是這樣,很高興你找到了它。 絕對不要把你的應用程序代碼長期放在Tomcat的lib /目錄下。 – 2010-05-03 23:28:07