I have a requirement to retrieve query params lets say clId,clCtx and clName from an odata uri and use them throughout the program across many classes. Retrieving the query params is an expensive process each time in our customised client framework. What is the best approach to retrieve and store the params once per request and utilise the same throughout the program?
My thoughts were to create a singleton class with a static java map as below. For the first time I can retrieve and store them in a map to use them later.
Also Would like to know Is my approach has any issues like memory leak or drawbacks.
public class ClientContainer {
private static Map<String,String> clientMap;
private static ClientContainer instance;
private ClientContainer(){}
public static ClientContainer getInstance(){
if(instance == null){
instance = new ClientContainer();
}
return instance;
}
private void updateClientMap(HashMap<String,String> clientMap){
if(this.clientMap==null){
this.clientMap =clientMap;
}
}
private HashMap<String,String> getClientMap(){
return this.clientMap;
}
}
Also Would like to know Is my approach has any issues like memory leak
or drawbacks.
1) Your ClientContainer class stores only the parameters for one client.
You use a Map<String,String> (values by param) in and not a Map<Client, Map<String, String>> (values by param and all that by client).
As you can instantiate a single time the class with the singleton pattern you are so stuck to store data not more than for one client request.
2) The lifespan of the requests (param-value) will be endless in this way.
The Map will indeed never be garbage collected as this is referenced by the singleton instance that has never a chance to be garbage collected too.
So if you keep the singleton pattern you should at least consider the key-values according to the client and you should also think to clean the cache at each time that a request was completely handled to avoid memory leak.
But If I was you, I probably would use another solution:
either I would create the Map as a local variable a single time : at the time where I receive the request and then I would pass it explicitly to each method that needs that.
or I would use ThreadLocal to store the Map if each request is handled by a specific thread.
Note that I prefer the first way that exposes clearly the dependency of the method.
Note also that using a Map is not necessary the best thing if the number of fields to use is stable and known : using a custom class may be much clearer, readable and more robust.
If you are using ClientContainer class in multithreading environment, then make sense to make getInstance() method thread-safe in order to avoid duplication of constructor. To avoid of memory leaks you can use WeakHashMap instead of HashMap.
Related
I have a static HashMap that is initialized on server startup. Clients initialize their data from this map when they login.
Now I need to refresh this map, but clients can login and get data from this map at the same time.
Can I change reference of map like below while they read?
I cant use synchronized because they can read in at the same time and only one thread is writing.
public void refresh() {
Map<String, Object> newMap = prepareData();
map = newMap;
}
Lets assume that "refresh" means that you want to replace all entries in the hashmap with a fresh set loaded from (say) a file.
If the set of keys in the new mapping is a superset of the keys in the original mapping, AND if you application doesn't care if clients can set part of the old mapping and part of the new mapping at the same time, then you could use a ConcurrentHashMap instead of a HashMap, and replace the entries with a sequence of put calls.
However, if keys are (or could be) different, or if the update needs to be atomic from the client's perspective then a ConcurrentHashMap is not going to work. Instead, you need to declare map as a volatile and implement your refresh() method as per your question.
As you point out, using synchronized (or a single-writer-multiple-reader lock) is liable to lead to a concurrency bottleneck.
Note: using a volatile is likely to give better performance than using a ConcurrentHashMap even in the cases where the latter is a viable solution.
First of all your map needs to be declared as volatile in order to ensure that each thread has the last version of it, then here is how you could proceed:
public void refresh() {
synchronized (MyClass.class) {
Map<String, Object> newMap = prepareData();
map = Collections.unmodifiableMap(newMap);
}
}
And your map would be declared as below:
private static volatile Map<String, Object> map = ...
If it's ok that clients have stale data, then all you need to do is create a new map and point your static reference at it. If a new client comes along while you're doing this then they get the stale data and no harm is done, if they turn up after the switch (reassignment) to the new values has occurred then they will get the new values. Job done.
If it's not ok then you will also, probably, have to inform other clients that existed before the update about the change. In which case you want to use the observer pattern for the updates. In this pattern it's fine if the client connects during the update, because they will be updated as soon as possible after the update is complete.
BTW: in all cases, you really shouldn't be using 'static' for anything. It'll only lead to problems down the line. Rather, create a non-static singleton that holds the map and inject that into your clients/services/whatever.
I am implementing a simple cache with the cache stored as an AtomicReference.
private AtomicReference<Map<String, String>> cacheData;
The cache object should be populated (lazily) from a database table.
I provide a method to return the cache data to a caller, but if the data is null (ie. not loaded), then the code needs to load the data from the database. To avoid synchronized I thought of using the compareAndSet() method:
public Object getCacheData() {
cacheData.compareAndSet(null, getDataFromDatabase()); // atomic reload only if data not set!
return Collections.unmodifiableMap(cacheData.get());
}
Is it ok to use compareAndSet in this way ie. to involve a database call as part of the atomic action? Is it any better/worse than just synchronizing the method?
Many thanks for any advice..
You do not achieve expected behaviour. This expression:
cacheData.compareAndSet(null, getDataFromDatabase())
will always call getDataFromDatabase() first. This means that it doesn't matter if the data was cached or not. If it was, you still call the database, but discard the results. The cache is working, but the performance is equally poor.
Consider this instead:
if(cacheData.get() == null) {
cacheData.compareAndSet(null, unmodifiableMap(getDataFromDatabase()));
}
return cacheData.get());
It's not perfect (still getDataFromDatabase() can be called multiple times at the beginning), but will work later as expected. Also I moved Collections.unmodifiableMap() earlier so that you don't have to wrap the same map over and over again.
Which brings us to even simpler implementation (no synchronized or AtomicReference needed):
private volatile Map<String, String> cacheData;
if(cacheData == null) {
cacheData = unmodifiableMap(getDataFromDatabase());
}
return cacheData;
I am attempting to implement thread-safe usage of ConcurentHashMap within singleton spring service that is injected into controllers:
#Service
public MyService{
final ConcurrentMap<String, AtomicInteger> myMap = new ConcurrentHashMap<String, AtomicInteger>(10) {
{/* initialize the ten key/values */
}
};
public int add(String key) {
return myMap.get(key).incrementAndGet();
}
// accessed via ajax loop (and controller), if value changes update display
public int getCount(String key) {
return myMap.get(key).get();
}
}
Is there a better way to make access to a hashmap thread-safe? How could I adapt this to work in a clustered environment? It is a follw up to my other question.
I do not aim to have an answer for the question esp. because I do not have expertise in the clustered situation; however, I'd like to point out what I think is worth noticing.
#JB Nizet in one of the comments mentions that the code is thread-safe and correct. I would like to add but not consistent based on Java API Reference:
Retrieval operations (including get) generally do not block, so may
overlap with update operations (including put and remove)
It means that there can be a client getting this information while some update is currently running. And, that makes sense since you mention 'looping' in your code. So, if this is NOT important in your case, then everything should be just fine.
But, if you need to make this more strict, I was thinking maybe using an instance of ReentrantReadWriteLock would be a good choice. The lock enables your code to block all the read requests until there is a consistent snapshot of the information available. You'd be probably using the lock on the getCount method to strictly block until add method frees all the locks waiting for the consistent snapshot of the map used in the code.
I also have a guess that the same concern is valid when you migrate this to a clustered solution; if consistency is required across different cluster nodes, then it should be taken care of.
I have an #ApplicationScoped bean for all users, that stores the ids-> names & vice versa in Trove & java.util maps.
I just build the maps once at construction of bean or (in case of manual refresh by the website admin).
Inside the bean methods, I am just using the get() with the maps, so not modifying the map. Is this going to be thread safe since it is used only for ready purposes? I am not sharing the maps with any other beans outside & not modifying the maps(adding/removing entries) anytime in my code.
Also, Is it neccesary in this case to make the fields final ?
Bean code as follows:
#ApplicationScoped
#ManagedBean(name="directory", eager=true)
public class directory {
private static TIntObjectHashMap<String> idsToNamesMap;
private static TreeMap<String, Integer> namesToIdsMap;
#PostConstruct
public void buildDirectory(){
// building directory here ....
}
public String getName(int topicId){
return idsToNamesMap.get(topicId);
}
public List<Entry<String, Integer>> searchTopicsByName(String query){
return new ArrayList(namesToIdsMap.subMap(query, true, query+"z", true).entrySet());
}
}
You don't have to declare them volatile or protect with any kind of synchronization in this case. As long as the constructing thread will build them and synchronize with the main memory.
For that the constructing thread need just to make a single write to a volatile variable or enter/exit a synchronization lock. This will pass a memory barrier and all local thread data will be in the main thread. Then it will be safe for all other threads to read this data.
Even more - unnecessary volatile or synchronization block - costs a serious performance penalty - on each access to the variable it will pass the memory barrier - which is an expensive operation
There could be a visibility issue after the object is constructed. That is, in the immediate aftermath of your constructor calls, the maps may appear populated to the thread that populated them, but not necessarily to other threads, at least not right away. This type of issue is extensively discussed in chapter 3 of Java Concurrency in Practice. However, I think that if you declare the maps as volatile:
private static volatile TIntObjectHashMap<String> idsToNamesMap;
private static volatile TreeMap<String, Integer> namesToIdsMap;
You should be OK.
Update
I just realized something while looking at your code again. The maps are static - why are they being populated in an instance context by a constructor? First off, it is confusing to the reader. Second, if more than one instance of the object is created, then you will have additional writes to the maps, not just one, possibly while other threads are reading them.
You should either make them non-static, or populate them in a static initialization block.
My developers and I are having an issue with objects being garbage collected in our application when we don't want them to be. We are using Java with Weblogic 10g3. We are programming a singleton pattern to handle all of our JMS connections.
There are two classes involved:
public class JMSObject {
...
private MessageProducer _producer;
private MessageConsumer _consumer;
...
// standard get/set procs... etc.
}
public class JMSFactory {
...
// Hashmap sessions with key == ConnectionFactory Name
Hashmap<String, List<Session>> _sessions;
// Hashmap of JMSObjects with key == ConnectionFactory Name + JMS Queue Name
Hashmap<String, List<JMSObject>> _jmsobjects;
...
// standard get/set & necessary sington functions
}
The init method of the Servlets calls the JMSFactory singlton method, any new Sessions are placed in the _sessions Hashmap and new MessageConsumer/MessageProducers are created as a JMSObject and placed in the _jmsobjects Hashmap, in the appropriate List.
The problem is that when the system is running the JMSObjects in the list get garbage collected after some time (sometimes in 5 minutes other times after a few hours.) We looked at this for a few days but could not find any reason for the JMSObjects to be garbarge collected. Since the JMSFactory has a reference to them why would the gc destroy them?
In the end we fixed it by changing the classes as follows(without changing method interfaces):
public class JMSObject {
...
private List<MessageProducer> _producers;
private List<MessageConsumer> _consumers;
...
// standard get/set procs... etc.
}
public class JMSFactory {
...
// Hashmap sessions with key == ConnectionFactory Name
Hashmap<String, List<Session>> _sessions;
// Hashmap of JMSObjects with key == ConnectionFactory Name + JMS Queue Name
private Hashmap<String JMSObject> _jmsobjects;
...
// standard get/set & necessary sington functions
}
So far in testing the JMSObjects are not being gc'ed. It has been running for 2 days.
Can someone explain why the indirect reference is causing the JMSObject to get gc'ed? And why the Sessions in the _sessions Hashmap was not getting gc'ed? Does it have anything to do with the fact the Sessions are built in Javax types and the JMSObject is something we wrote?
Since the JMSFactory has a reference to them why would the gc destroy them?
Well, are any objects still holding reference to the JMSFactory at this point?
Typical singleton pattern keeps the reference to the singleton object in a static member:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
//constructor...
}
public static Singleton getInstance() { return instance; }
}
Is this not the pattern you are following? It is not possible to tell from the code you provided in your post, as you left out the actual singleton code...
(BTW, using Singletons for something like this sounds like it would cause pains, besides being hard to test. See Singletons Are Pathlogical Liars)
I think I know what your problem is, it's something I ran into a while back (on WebLogic 6). I believe it has to do with WebLogic's dynamic class reloading, which WebLogic seems to do from time to time, even when you're not in a development environment (I'm guessing the web.xml is somehow getting touched by some service or something).
What happened in our case was that like you, we have a single instance of an object that's defined as a static variable of some class, and just like you, it's initialized by a servlet that has it's load-on-startup parameter set. When WebLogic thinks there's a change, it reloads the webapp by garbage collecting the classloader (which is fine) but it doesn't re-initialize all the servlets that are marked "load-on-startup" (in our case, and I'm guessing yours, the servlet serves no purpose other than to initialize the static variable, there are no mappings to it, and so it cannot be invoke, the static variable gets GCed, but not-reinitialized, and the server needs to be restarted.
In our case, our solution was to initialize the static variable in a static initializer. The original developer used a servlet to initialize the variable because he wanted some servlet context information, which really wasn't necessary. If you need context information, you could try doing your initialization in a ServletContextListener.
Without having all of the code this a tough question to solve. But there are tools to help out.
Try this link: http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/
It provides information about using jhat and jmap. Although the article is written to find memory leaks, it provides info on how to keep track of references to an object. Maybe you can track down why your references are disappearing.
You said the Sessions in the _sessions map were not being GC'd, but the JMSObjects were not. I doubt it's because it is something you wrote. It sounds like either the JMSFactory itself is being collected (i.e. singleton not implemented properly) or something is removing the keys from the maps. In either case, the JMSObjects would be eligible for GC, but the session objects would not because the list still has a reference to them.
Any chance that the classloader that loaded the JMSFactory was being unloaded, causing the JMSFactory class to be GC'ed (including the singleton instance), which frees up the HashMaps and their contents?