• Post Reply Bookmark Topic Watch Topic
  • New Topic

Singleton Thread Safety  RSS feed

 
James Davison
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My goal is to implement a class as a Singleton that will read a small reference table from a database. My questions are these:
1) Should I maintain the data in a Hashtable or HashMap? My question has to do with the getter method that retrieves a value. If I use a Hashtable (or HashMap), is it necessary to synchonize the getter method? If using a Hashtable, I would think no because it is a synchronized Collection. If using a HashMap, I would suspect I would.
2) I want to include a refresh() method that will refresh the Hashtable/HashMap values daily or upon request. Since this class is a Singleton, I plan only to declare the instance variable as static but declare the Hashtable/HashMap as an an instance variable. Therefore, it seems to me that the refresh() method would not need to be declared static, just synchronized as it is the only method that will update the Hashtable/HashMap for the Singleton instance. Is this correct?
3) Depending upon the previous answers: If the refresh() method is declared as synchronized but the getter method is NOT, will invocations of the getter method be blocked while the refresh() method is executing? I don't want to fail retrieving a value while the class is refreshing itself.
Thanks for your responses.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
1) Should I maintain the data in a Hashtable or HashMap? My question has to do with the getter method that retrieves a value. If I use a Hashtable (or HashMap), is it necessary to synchonize the getter method? If using a Hashtable, I would think no because it is a synchronized Collection. If using a HashMap, I would suspect I would.
If you're accessing the map through multiple threads, and the contents of the map are not constant, then you'd want some sort of synchonization. A Hashtable would work, or a Collections.synchronizedMap(new HashMap()). Or you could just synchronize the method in the singleton class which accesses the map.
However it sounds like the data in the map is static, except for when you refresh. In this case you could really omit synchonization altogether, except maybe on the refresh(). At that time, you can just replace your HashMap with a new HashMap containing the latest data. It's possible that some threads will not immediately recognize that the map has been replaced, because they've cached a reference to the original map. (JVMs are allowed to do this in non-synchonized code if the variable is not declared volatile). But I doubt this effect would be observable more than a few seconds after the refresh(), which is probably insignificant for your application. To be safe though, you could simply declare the map reference to be volatile. This will still be faster than any form of synchronization would be.
2) I want to include a refresh() method that will refresh the Hashtable/HashMap values daily or upon request. Since this class is a Singleton, I plan only to declare the instance variable as static but declare the Hashtable/HashMap as an an instance variable. Therefore, it seems to me that the refresh() method would not need to be declared static, just synchronized as it is the only method that will update the Hashtable/HashMap for the Singleton instance. Is this correct?
Correct. (Assuming you don't choose to follow my advice above about using volatile rather than synchronization here.)
3) Depending upon the previous answers: If the refresh() method is declared as synchronized but the getter method is NOT, will invocations of the getter method be blocked while the refresh() method is executing?
No.
I don't want to fail retrieving a value while the class is refreshing itself.
Well, you may fail precisely because the get() is proceeding concurrently with a refresh. If structure of a HashMap is changing while a get() takes place (i.e. if the bucket array is being resized and/or the entries are being rehashed) then the behavior of the HashMap is not guaranteed. You may get a NullPointerException, ArrayIndexOutOfBoundsException, ConcurrectModificationException, or something else. It would be better to delay the query, IMO, but this depends on whether speed or accuracy is more important in your application.
However my previous suggestion will still work fine. If you are replacing the map with a different map, rather than changing the contents of a single map, then there's no problem. Depending on your timing, you'll either get data from the old map, or the new map, but never from a map whose contents are changing.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!