Good morning, I am currently developing a java web application that exposes a web service interface. In order to keep a global object in memory, I use the following class as a 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;
}
}
I am using the above class in order to have the same instance of the HashMap for all the threads of the web service. The Web service class that maintains the SingletonMap object is the following:
@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();
}
}
The reason i have the method getCouponMapCreationTime() is to check that all the threads of the web service are accessing the same object. Is the above approach correct? How about performance overheads? Do you think I need the Singleton properties, or could I just use a static HashMap for all the threads? If I use a static HashMap, is it going to be garbage collected in case no thread is active?
Thank you for your time.
JAX-WS has its own patterns for creating singletons, you don't need to use static fields. You use the
@Inject
annotation into each service. See this blog post: http://weblogs.java.net/blog/jitu/archive/2010/02/19/jax-ws-cdi-java-ee-6-0 (but don't use@SessionScoped
, use@Singleton
)Some other points:
HashMap
isn't thread-safe, you needConcurrentHashMap
.This
catch(NamingException e) { System.err.println(e.getMessage());
is unhelpful. Rethrow it as aRuntimeException
. You can't recover from it.Don't worry about performance overhead at this stage. Measure it once you have something working.
A JAX-WS web service is by itself a Singleton. This means that all the request will be handled using a single web service instance (like a Servlet).
So, any member of the class will be 'shared' between all the request. In your case, you do not need to make your members (i.e. couponMap) an static attributes.
Conclusion: Don't worry, all your threads (request) will be accessing the same 'couponMap'. Because you don't need the
getCouponMapCreationTime
anymore, I think that you can eliminate theSingletonMap
abstraction and use directly a Map in your web service class.But I have something very important to add. If several threads (request) will be accessing your Map you have to make it thread-safe!!! There are a lot of way to do this, but I will give an idea: Use a
ConcurrentHashMap
instead of aHashMap
. This will make all yourget(), put(), remove()
operations thread-safe! If you need a larger scope you can use synchronized blocks, but please avoid synchronize methods because the scoop is too large and always synchronize overthis
object.