Can hazelcast IMap be used only for the purpose of locking? - java

Currently as far as I'm aware, you don't need to use any destroy methods after using IMap#tryLock unlike ILock.
Would it be a good or bad practice to change all ILocks retrieved from HazelcastInstance to IMaps and use code similar to what shown below?
public final T execute(){
try{
imapForLocking.tryLock(nonexistentInMapStringKey);
return executeCodeUnrelatedToMap();
}finally{
imapForLocking.unlock(nonexistentInMapStringKey);
}
}

Found my answer here https://groups.google.com/forum/#!topic/hazelcast/9YFGh3xwe8I
It is encouraged by hazelcast developers to use IMap for locking instead of ILock
Yes you have to call destroy as all ILock objects are kept in memory.
You can also use a distributed map for your locks:
IMap mapLocks = hazelcastInstance.getMap("mylocks");
mapLocks.lock(theKey);
when you call mapLocks.unlock(theKey), your lock is
auto-garbage-collected. This is simpler, faster and cleaner.

Why do you think you don't need any destroy method?
Probably you should always keep the lock/try/finally/unlock pattern since eventually the lock might need to timeout before being released.
iMap.lock("foo");
try {
// do something else
} finally {
iMap.unlock("foo");
}
But actually if you have the feeling you need to lock the map to do some changes you might want to look forward to use EntryProcessor which will run on the key owner and provides you with an implicit lock, so you don't actually need real locking but have the same behavior.
Locking itself is always a costly and non preferable operation.

Related

Can a striped lock be used to synchronize a map?

I don't know why I can't get my head around this question.
I see examples on the internet where people talk about using striped locking to synchronize a map. The idea is to use multiple locks to allow for more concurrency, while retaining correctness. But is an approach like this actually correct?
I believe that the idea is to have one lock per bucket, the same thing that ConcurrentHashMap does under the hood, but how can one achieve such a feat given the fact the the mapping key -> bucket is an internal Map implementation detail, and is not actually possible to match it from the outside of the Map?
Take this example:
public void concurrentMethod(String key) {
val lock = stripedLock.get(key))
lock.lock()
// do work on map[key]
lock.unlock()
}
there's no guarantee that stripedLocks.get(key) will return the same lock for 2 keys that will end up in the same bucket. So, as far as I can tell, this is not correct and the synchronization doesn't actually work.
Is my reasoning wrong here? Can an approach like this lead to correct synchronization?

Java multi threading atomic assignment

Same with the follow link, I use the same code with the questioner.
Java multi-threading atomic reference assignment
In my code, there
HashMap<String,String> cache = new HashMap<String,String>();
public class myClass {
private HashMap<String,String> cache = null;
public void init() {
refreshCache();
}
// this method can be called occasionally to update the cache.
//Only one threading will get to this code.
public void refreshCache() {
HashMap<String,String> newcache = new HashMap<String,String>();
// code to fill up the new cache
// and then finally
cache = newcache; //assign the old cache to the new one in Atomic way
}
//Many threads will run this code
public void getCache(Object key) {
ob = cache.get(key)
//do something
}
}
I read the sjlee's answer again and again, I can't understand in which case these code will go wrong. Can anyone give me a example?
Remember I don't care about the getCache function will get the old data.
I'm sorry I can't add comment to the above question because I don't have 50 reputation.
So I just add a new question.
Without a memory barrier you might see null or an old map but you could see an incomplete map. I.e. you see bits of it but not all. Thus is not a problem if you don't mind entries being missing but you risk seeing the Map object but not anything it refers to resulting in a possible NPE.
There is no guarantee you will see a complete Map.
final fields will be visible but non - final fields might not.
this is a very interesting problem, and it shows that one of your core assumptions
"Remember I don't care about the getCache function will get the old
data."
is not correct.
we think, that if "refreshCache" and "getCache" is not synchronized, then we will only get old data, which is not true.
Their call by the initial thread may never reflect in other threads. Since cache is not volatile, every thread is free to keep it's own local copy of it and never make it consistent across threads.
Because the "visibility" aspect of multi-threading, which says that unless we use appropriate locking, or use volatile, we do not trigger a happens-before scenario, which forces threads to make shared variable value consistent across the multiple processors they are running on, which means "cache" , may never get initialized causing an obvious NPE in getCache
to understand this properly, i would recommend reading section 16.2.4 of "Java concurrency in practice" book which deals with a similar problem in double checked locking code.
Solution: would be
To make refreshCache synchronized to force, all threads to update their copy of HashMap whenever any one thread calls it, or
To make cache volatile or
You would have to call refreshCache in every single thread that calls getCache which kind of defeats the purpose of a common cache.

Missing items from synchronized HashMap in a threaded environment

I know you have to synchronize around anything that would change the structure of a hashmap (put or remove) but it seems to me you also have to synchronize around reads of the hashmap otherwise you might be reading while another thread is changing the structure of the hashmap.
So I sync around gets and puts to my hashmap.
The only machines I have available to me to test with all only have one processor so I never had any real concurrency until the system went to production and started failing. Items were missing out of my hashmap. I assume this is because two threads were writing at the same time, but based on the code below, this should not be possible. When I turned down the number of threads to 1 it started working flawlessly, so it's definitely a threading problem.
Details:
// something for all the threads to sync on
private static Object EMREPORTONE = new Object();
synchronized (EMREPORTONE)
{
reportdatacache.put("name.." + eri.recip_map_id, eri.name);
reportdatacache.put("subjec" + eri.recip_map_id, eri.subject);
etc...
}
... and elsewhere....
synchronized (EMREPORTONE)
{
eri.name = (String)reportdatacache.get("name.." + eri.recip_map_id);
eri.subject = (String)reportdatacache.get("subjec" + eri.recip_map_id);
etc...
}
and that's it. I pass around reportdatacache between functions, but that's just the reference to the hashmap.
Another important point is that this is running as a servlet in an appserver (iplanet to be specific, but I know none of you have ever heard of that)
But regardless, EMREPORTONE is global to the webserver process, no two threads should be able to step on each other, yet my hashmap is getting wrecked. Any thoughts?
In servlet container environment static variables depend on classloader. So you may think that you're dealing with same static instance, but in fact it could be completely different one.
Additionally, check if you do not use the map by escaped reference elsewhere and write/remove keys from it.
And yes, use ConcurrentHashMap instead.
Yes, synchronization is not only important when writing, but also when reading. While a write will be performed under mutually exclusion, a reader might access an errenous state of the map.
I cannot recommend you under any circumstances to synchronize the Java Collections manually, there are thread-safe counterparts: Collections.synchronizedMap and ConcurrentHashMap. Use them, they will ensure, that access to them is safe in a multithreaded environment.
Futher hints, it seems that everyone is accesing the datareportcache. Is there only one instance of that object? Why not synchronize then on the cache itself? But forget then when trying to solve your problems, use the sugar from java.util.concurrent.
As I see it there are 3 possibilities here:
You are locking on two different objects. EMREPORTONE is private static however and the code that accesses the reportdatacache is in one file only. Ok, that isn't it then. But I would recommend locking on reportdatacache instead of EMREPORTONE however. Cleaner code.
You are missing some read or write to reportdatacache somewhere. There are other accesses to the map that are not synchronized. Are things never removed from the cache?
This isn't a synchronization problem but rather a race condition issue. The data in the hashmap is fine but you are expecting things to be in the cache but they haven't be stored by the other thread yet. Maybe 2 requests come in for the same eri at the same time and they are both putting values into the cache? Maybe check to see if the old value returned by put(...) is always null? Maybe explaining more about how you know that items are missing from the map would help with this.
As an aside, you are doing this:
reportdatacache.put("name.." + eri.recip_map_id, eri.name);
reportdatacache.put("subjec" + eri.recip_map_id, eri.subject);
But it seems like you really should be storing the eri by its id.
reportdatacache.put(recip_map_id, eri);
Then you aren't creating fake keys with the "name.." prefix. Or maybe you should create a NameSubject private static class to store the name and subject in the cache. Cleaner.
Hope something here helps.

Using ConcurentHashMap and AtomicInteger as instance variables within a spring service class

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.

Synchronized Map or synchronized methods

I have the following class for a Router's table with synchronised methods:
public class RouterTable {
private String tableForRouter;
private Map<String,RouterTableEntry> table;
public RouterTable(String router){
tableForRouter = router;
table = new HashMap<String,RouterTableEntry>();
}
public String owner(){
return tableForRouter;
}
public synchronized void add(String network, String ipAddress, int distance){
table.put(network, new RouterTableEntry(ipAddress, distance));
}
public synchronized boolean exists(String network){
return table.containsKey(network);
}
}
Multiple threads will read and write to the HashMap. I was wondering if it would be best to remove the synchronized on the methods and just use Collections.synchronizedMap(new HashMap<String,RouterTableEntry())` what is the most sensible way in Java to do this?
I would suggest using a ConcurrentHashmap. This is a newer data structure introduced in later version of Java. It provides thread safety and allows concurrent operations, as opposed to a synchronized map, which will do one operation at a time.
If the map is the only place where thread safety is required, then just using the ConcurrentHashmap is fine. However, if you have atomic operations involving more state variables, I would suggest using synchronized code blocks instead of synchronized functions
In the absence of strict requirements about happens-before relationships and point in time correctness, the sensible thing to do in modern java is usually just use a ConcurrentMap.
Otherwise, yes, using a Collections#synchronizedMap is both safer and likely more performant (because you won't enclose any tertiary code that doesn't need synchronization) than manually synchronizing everything yourself.
The best is to use a java.util.concurrent.ConcurrentHashMap, which is designed from the ground up for concurrent access (read & write).
Using synchronization like you do works, but shows high contention and therefore not optimal performance. A collection obtained through Collections.synchronizedMap() would do just the same (it only wraps a standart collection with synchronized methods).
ConcurrentHashMap, on the contrary, used various techniques to be thread-safe and provide good concurrency ; for example, it has (by default) 16 regions, each guarded by a distinct lock, so that up to 16 threads can use it concurrently.
Synchronizing the map will prevent users of your class from doing meaningful synchronization.
They will have no way of knowing if the result from exists is still valid, once they get into there if statement, and will need to do external synchronization.
With the synchronized methods as you show, they could lock on your class until they are done with a block of method calls.
The other option is to do no synchronization and let the user handle that, which they need to do anyway to be safe.
Adding your own synchronization is what was wrong with HashTable.
The current common style tends to prefer Synchronized collections over explicit synchronized qualification on the methods that access them. However, this is not set in stone, and your decision should depend on the way you use this code/will use this code in the future.
Points to consider:
(a) If your map is going to be used by code that is outside of the RouterTable then you need to use a SynchronizedMap.
(b) OTOH, if you are going to add some additional fields to RouterTable, and their values need to be consistent with the values in the map (in other words: you want changes to the map and to the additional fields to happen in one atomic quantum), then you need to use synchrnoized method.

Categories