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.
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.
In Java, Singleton is a design pattern that ensures that a class can only have one object. To create a singleton class, a class must implement the following properties: Create a private constructor of the class to restrict object creation outside of the class.
A Singleton object is an object which defines a single object of a class. A singleton object provides an entry point to your program execution. If you do not create a singleton object in your program, then your code compile successfully but does not give output.
It is used where only a single instance of a class is required to control the action throughout the execution. A singleton class shouldn't have multiple instances in any case and at any cost. Singleton classes are used for logging, driver objects, caching and thread pool, database connections.
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 the SingletonMap
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 a HashMap
. This will make all your get(), 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 over this
object.
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 need ConcurrentHashMap
.
This catch(NamingException e) { System.err.println(e.getMessage());
is unhelpful. Rethrow it as a RuntimeException
. You can't recover from it.
Don't worry about performance overhead at this stage. Measure it once you have something working.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With