Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fine-grained synchronization/locking of method calls based on method parameters

I want to synchronize method calls on basis some id i.e. something like a concurrency Decorator of a given object instance.
For example:
All threads which call the method with param "id1", should execute serially to one another.
All of the rest, which call the method with different argument, say "id2", should execute in parallel to the threads which call the method with param "id1", but again serially to each other.

So in my mind this can be implemented by having a lock (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantLock.html) instance per such method param. Each time the method is called with the param, the lock instance corresponding to the specific param value (e.g. "id1") would be looked up and the current thread would try to obtain the lock.

Speaking in code:

public class ConcurrentPolicyWrapperImpl implements Foo {

private Foo delegate;

/**
* Holds the monitor objects used for synchronization.
*/
private Map<String, Lock> concurrentPolicyMap = Collections.synchronizedMap(new HashMap<String, Lock>());

/**
* Here we decorate the call to the wrapped instance with a synchronization policy.
*/
@Override
public Object callFooDelegateMethod (String id) {
        Lock lock = getLock(id);
        lock.lock();
        try {
            return delegate.delegateMethod(id);
        } finally {
            lock.unlock();
        }
}


protected Lock getLock(String id) {
        Lock lock = concurrentPolicyMap.get(id);

        if (lock == null) {
            lock = createLock();
            concurrentPolicyMap.put(id, lock);

        }
        return lock;
    }

}

protected Lock createLock() {
        return new ReentrantLock();
    }

It seems that this works - I did some performance testing with jmeter and so on. Still, as we all know concurrency in Java is a tricky thing, I decided to ask for your opinion here.

I can't stop thinking that there could be a better way to accomplish this. For example by using one of the BlockingQueue implementations. What do you think?

I also can't really decide for sure if there is a potential synchronization problem with getting the lock i.e. the protected Lock getLock(String id) method. I am using a synchronized collection, but is that enough? I.e. shouldn't it be something like the following instead of what I currently have:

protected Lock getLock(String id) {
  synchronized(concurrentPolicyMap) {
    Lock lock = concurrentPolicyMap.get(id);

    if (lock == null) {
      lock = createLock();
      concurrentPolicyMap.put(id, lock);

    }
    return lock;
  }

}

So what do you guys think?

like image 591
Svilen Avatar asked May 30 '13 15:05

Svilen


People also ask

Which lock is used for synchronized method?

When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.

Does synchronized method lock object?

When a method is declared as synchronized; the thread holds the monitor or lock object for that method's object. If another thread is executing the synchronized method, your thread is blocked until that thread releases the monitor.

What does the JVM lock on for synchronized methods?

The JVM uses locks in conjunction with monitors. A monitor is basically a guardian in that it watches over a sequence of code, making sure only one thread at a time executes the code. Each monitor is associated with an object reference.

Which of the following interfaces specifies the type of lock maintaining a pair of locks for read and write access?

ReadWriteLock. The interface ReadWriteLock specifies another type of lock maintaining a pair of locks for read and write access.


1 Answers

Lock creation issues aside, the pattern is OK except that you may have an unbounded number of locks. Generally people avoid this by creating/using a Striped lock. There is a good/simple implementation in the guava library.

Application area of lock-striping

How to acquire a lock by a key

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/util/concurrent/Striped.html

Example code using guava implementation:

private Striped<Lock> STRIPPED_LOCK = Striped.lock(64);

public static void doActualWork(int id) throws InterruptedException {
    try {
        STRIPPED_LOCK.get(id).lock();
        ...
    } finally {
        STRIPPED_LOCK.get(id).unlock();
    }
}
like image 98
Keith Avatar answered Sep 28 '22 04:09

Keith