Re: Avoiding race conditions with Hazelcast Map

2,226 views
Skip to first unread message

Mehmet Dogan

unread,
Dec 18, 2012, 2:14:46 PM12/18/12
to haze...@googlegroups.com
You can use map.replace(key, oldValue, newValue);

Value v = map.get(key);
if (v.hasSomeConditionMet())
{
   Value newV = new Value(...);
   map.replace(key, v, newV);
}

Or you can use locks;

if (map.tryLock(key)) {
    Value v = map.get(key);
    if (v.hasSomeConditionMet())
    {
       v = new Value(...);
       map.put(key, v);
    }
}



@mmdogan




On Tue, Dec 18, 2012 at 8:14 PM, Matt <matt...@alfresco.com> wrote:
I'm confused as to how one handles concurrency with Hazelcast distributed data structures. For example, I need to be able to do the following:

Value v = map.get(key);
if (v.hasSomeConditionMet())
{
   v = new Value(...);
   map.put(v);
}

Won't this result in a check-then-act race condition where two cluster members both put the new value - supposing I want only one cluster member to win?

Is there any way to achieve this atomically in a way similar to putIfAbsent()?

Thanks.

--
 
 

Tim Peierls

unread,
Dec 18, 2012, 2:21:34 PM12/18/12
to haze...@googlegroups.com
On Tue, Dec 18, 2012 at 2:14 PM, Mehmet Dogan <meh...@hazelcast.com> wrote:
You can use map.replace(key, oldValue, newValue);

Value v = map.get(key);
if (v.hasSomeConditionMet())
{
   Value newV = new Value(...);
   map.replace(key, v, newV);
}

A variation on that theme that is sometimes useful:

Value v = map.get(key);
while (v != null && v.hasSomeConditionMet() && !map.replace(key, v, new Value(...)))
{
    v = map.get(key);
}


 
Or you can use locks;

if (map.tryLock(key)) {
    Value v = map.get(key);
    if (v.hasSomeConditionMet())
    {
       v = new Value(...);
       map.put(key, v);
    }
}

But don't forget to release the lock in a finally block!

--tim 

Matt

unread,
Dec 20, 2012, 5:42:17 AM12/20/12
to haze...@googlegroups.com
Brilliant - I didn't know about maps having locks available on them, looks like just what I need.

I guess this means I must always use locking when access the map, even if just checking a value elsewhere? (i.e. if this were a multi-threaded java discussion I would say that if a member variable needs synchronisation then it must always use synchronisation everywhere it is accessed)

e.g. elsewhere in the code

bad:

Value v = map.get(k);
...

good:

if (map.tryLock(k))
{
   try
   {
      Value v = map.get(k);
   }
   finally
   {
      map.unlock(k);
   }
}
(or using the tryLockAndGet(...) method)

Also, I notice that tryLock(...) is non-blocking, as opposed to the ReentrantReadWriteLock I am used to - would you normally loop/sleep to ensure the work gets done or is there a different pattern of usage I should be examining?

Thanks again

Mehmet Dogan

unread,
Dec 20, 2012, 6:24:26 AM12/20/12
to haze...@googlegroups.com
You don't need locking when just accessing a single value. Hazelcast map is a ConcurrentMap, you will (should) read most recent value always. I did not understand why you are thinking you need to lock while reading?

As far as I know "tryLock()" immediately returns true or false without blocking/waiting (or second version  tryLock(time, unit) waits at most given time). This behaviour applies to both Hazelcast lock and JDK ReentrantLock.


@mmdogan

Matt

unread,
Dec 20, 2012, 6:40:55 AM12/20/12
to haze...@googlegroups.com
I guess whether you need to lock on a read depends on the nature of the state you are guarding (if you are setting multiple values, e.g. some outside the map, then you need to synchronise on read) - in most cases I suppose you wouldn't have to.

WRT ReentrantLock, from the javadocs for lock():

If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired, at which time the lock hold count is set to one.


It does block, otherwise what would you do if you need to lock an object and do something with it - hence my question about sleep/loop.

Indeed the Hazelcast lock does seem to have different semantics:

If the lock is not available then the current thread doesn't wait and returns false immediately.


So how are you dealing with the situation where it can't acquire the lock?

Thanks

Mehmet Dogan

unread,
Dec 20, 2012, 6:53:25 AM12/20/12
to haze...@googlegroups.com
We were talking about tryLock() not lock(). Even I never mentioned about lock()

@mmdogan



--
You received this message because you are subscribed to the Google Groups "Hazelcast" group.
To post to this group, send email to haze...@googlegroups.com.
To unsubscribe from this group, send email to hazelcast+...@googlegroups.com.
Visit this group at http://groups.google.com/group/hazelcast?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Matt

unread,
Dec 20, 2012, 6:59:00 AM12/20/12
to haze...@googlegroups.com
OK, I feel silly now - so there is the blocking lock() call available on IMap (I'll be sure to read the Hazelcast javadocs next time - I had been relying on the other documentation which does not mention IMap locking).

This makes things an awful lot easier all of a sudden - I now know what I need to do.

Thanks very much for your help!
Reply all
Reply to author
Forward
0 new messages