Java Web服务中的Singleton对象

早上好,我正在开发一个公开Web服务接口的java Web应用程序。 为了将全局对象保留在内存中,我将以下类用作Singleton:

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; } } 

我正在使用上面的类,以便为Web服务的所有线程提供相同的HashMap实例。 维护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,如果没有线程处于活动状态,它是否会被垃圾收集?

感谢您的时间。

JAX-WS Web服务本身就是一个Singleton。 这意味着将使用单个Web服务实例(如Servlet)处理所有请求。

因此,该类的任何成员都将在所有请求之间“共享”。 在您的情况下,您不需要使您的成员(即couponMap)成为静态属性。

结论:不用担心,所有线程(请求)都将访问相同的“couponMap”。 因为您不再需要getCouponMapCreationTime ,我认为您可以消除SingletonMap抽象并直接在Web服务类中使用Map。

但我有一些非常重要的补充。 如果几个线程(请求)将访问您的地图,您必须使其线程安全! 有很多方法可以做到这一点,但我会提出一个想法:使用ConcurrentHashMap而不是HashMap 。 这将使你的所有get(), put(), remove()操作都是线程安全的! 如果您需要更大的范围,则可以使用synchronized块,但请避免使用同步方法,因为scoop太大并且始终在this对象上进行同步。

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. 在此阶段不要担心性能开销。 一旦你有工作,测量它。