2012-06-19 37 views
4

早上好, 我目前正在開發一個公開Web服務接口的Java Web應用程序。爲了保持一個全局對象在內存中,我用下面的類作爲一個Singleton:Java Web服務中的單例對象

public class SingletonMap { 
    private static final SingletonMap instance = new SingletonMap(); 
    private static HashMap couponMap = null; 
    private static long creationTime; 

    private SingletonMap() { 
     creationTime = System.currentTimeMillis(); 
     couponMap = new HashMap(); 
    } 

    public static synchronized SingletonMap getInstance() { 
     return instance; 
    } 

    public static long getCreationTime() { 
     return creationTime; 
    } 
} 

我纔能有HashMap中的同一個實例爲Web服務的所有線程使用上述類。即保持SingletonMap對象的Web服務類如下:

@WebService() 
public class ETL_WS { 
    private String TOMCAT_TEMP_DIR; 
    private final int BUFFER_SIZE = 10000000; 
    private static SingletonMap couponMap; 
    private static SingletonProductMap productCategoryMap; 
    private String dbTable = "user_preferences"; 

    public ETL_WS() { 
     Context context = null; 
     try { 
      context = (Context) new InitialContext().lookup("java:comp/env"); 
      this.TOMCAT_TEMP_DIR = (String) context.lookup("FILE_UPLOAD_TEMP_DIR"); 
     }catch(NamingException e) { 
     System.err.println(e.getMessage()); 
    } 

    public long getCouponMapCreationTime() { 
     return couponMap.getCreationTime(); 
    } 

} 

因爲我這方法getCouponMapCreationTime()是檢查Web服務的所有線程都訪問同一個對象。上述方法是否正確?性能開銷如何?你認爲我需要Singleton屬性,還是我可以爲所有線程使用靜態HashMap?如果我使用靜態HashMap,在沒有線程處於活動狀態時是否會收集垃圾?

謝謝你的時間。

回答

7

JAX-WS web服務本身就是一個單例。這意味着所有請求都將使用單個Web服務實例(如Servlet)進行處理。

因此,該類的任何成員將在所有請求之間「共享」。在你的情況下,你不需要讓你的成員(即couponMap)成爲一個靜態屬性。

結論:不用擔心,所有的線程(請求)都將訪問相同的'couponMap'。因爲您不再需要getCouponMapCreationTime了,我認爲您可以消除SingletonMap抽象並直接在Web服務類中使用Map。

但我有一些非常重要的補充。如果多個線程(請求)將訪問您的地圖,您必須使其線程安全!有很多方法可以做到這一點,但我會給出一個想法:使用ConcurrentHashMap而不是HashMap。這將使您的所有get(), put(), remove()操作線程安全!如果您需要更大範圍,則可以使用同步塊,但請避免同步方法,因爲瓢太大並始終通過this對象進行同步。

+0

我明白了。如果客戶端請求之間有很大的停頓,該對象是否會被垃圾收集,或者不是?我的意思是,如果Web服務空閒一段時間,JVM是否運行垃圾回收器並清理我的實例?對不起,如果我很煩人,但我是這個領域的新手,並且我從未部署過帶有持久內存(RAM)對象的Web服務。 –

+2

不,對象將永遠不會被垃圾收集,因爲框架保留對它的引用。這些類型的框架(servlet,jaxws等)總是保留服務對象的單個實例,但它們實際創建/銷燬的是線程(使用線程池策略)。但不要擔心,這不會影響您的內存共享數據! – ggarciao

+0

謝謝ggarciao。你的快速回答幫了我很多。 –

3

JAX-WS有自己創建單例模式,您不需要使用靜態字段。您在每個服務中使用@Inject註釋。看到這個博客帖子:http://weblogs.java.net/blog/jitu/archive/2010/02/19/jax-ws-cdi-java-ee-6-0(但不使用@SessionScoped,使用@Singleton

的其他一些觀點:

  1. HashMap不是線程安全的,你需要ConcurrentHashMap

  2. catch(NamingException e) { System.err.println(e.getMessage());是無益的。重新將它作爲RuntimeException。你無法從中恢復。

  3. 不要擔心現階段的性能開銷。一旦你有一些工作,測量它。

+1

謝謝您的快速回答。我檢查了你發佈的鏈接,但確定所有的線程都會使用我的SingletonMap類的同一個實例嗎?實際上,我所使用的SingletonMap對象應該被初始化一次(懶惰),被所有Web服務線程使用,並且只有在Web服務關閉時才被銷燬。 P.S. .:謝謝你的觀點:) –