I was trying to write a singleton class, which will be used for simple cache implementation. I followed a double checked locking pattern for getting the instance where the instance is a volatile member inside the class. It also contains a HashTable for storing the data.
If I am trying to access a value inside the map through a method, should I provide 'synchronized' keyword for blocking concurrent access?. I am asking this question because the UserCache itself is syncronized using double-checked-locking in the getInstance() method
Or is it better to use a ConcurrentHashMap instead of HashTable?
See the code snippet below for more details.
public class UserCache {
private volatile static UserCache instance;
private Hashtable<String, User> users = null;
private UserCache() {
this.users = new Hashtable<String, User>();
}
public static UserCache getInstance() {
if (instance == null) {
synchronized (UserCache.class) {
if (instance == null) {
instance = new UserCache();
}
}
}
return instance;
}
public synchronized User getUser(String userUid) {
return this.users.get(userUid);
}
public synchronized boolean addUser(User user) {
if (isValidUser(user.getUserUid())) {
return false;
}
this.users.put(user.getUserUid(), user);
return true;
}
...
Any advice would be greatly appreciated :)
Thanks in advance
If that is the extent of your class, then a ConcurrentHashMap would work. If you have any additional methods where more than a simple get/put to the map needs to be synchronized, a ReadWriteLock is a good option to allow concurrent reads.
Another alternative to your double checked locking with a volatile static would be to use an inner class:
private static final class DeferredLoader {
static final UserCache INSTANCE = new UserCache();
}
public static UserCache getInstance() {
return DeferredLoader.INSTANCE;
}
This has the advantage of being immutable and still defers the creation of the instance until the getInstance method is called the first time.