Question

In my spring web app, I have a service method containing a block of code guarded by a lock. Only a single thread can enter the code block at a time. This works fine in a non clustered environment but fails in a clustered one. In a clustered environment, within a node, synchronization happens but among different nodes, code block is executed in parallel. Is this because in each node a separate Lock object is created ? Can anyone advise me ?

Code Sample

//Service Class
@Service
class MyServiceClass {

private final Lock globalLock;

@Autowired
public MyServiceClass(@Qualifier("globalLock") final Lock globalLock){
    this.globalLock = globalLock;
}

public void myServiceMethod(){
    ...
    globalLock.lock();
    try {
        ...
    }
    finally {
        globalLock.unlock();
    }
    ...

}

}//End of MyServiceClass


//Spring Configuration XML
<bean id="globalLock" class="java.util.concurrent.locks.ReentrantLock" scope="singleton" />
Was it helpful?

Solution

If you want to synchronize objects in a cluster environment, this meaning many VMs involved, your solution would involve some kind of communication between the different VMs involved.

In this case, it will require some imagination to get the thing done: you will need the mutual exclusion implemented on some object that is common to all the VMs involved, and that may escalate when you put additional machines into the cluster. Have you thought some solution based on JNDI? Here you have something on it, but I am afraid it looks rather an academic discussion:

http://jsr166-concurrency.10961.n7.nabble.com/Lock-implementation-td2180.html

There is always the chance to implement something based on DB mechanisms (always thinking that your DB is a central and common resource to all the nodes in the cluster). You could devise something based on some SELECT FOR UPDATE mechanism implemented in your database, over some table used only for synchronization...

You have an interesting problem! :) Good luck

OTHER TIPS

You are right, the reason is that each node has it's own lock. To solve this, consider introducing in the database a table SERVICE_LOCKS, with the columns service class name, service Id, lock status and acquisition timestamp.

For service Id make each service generate a unique distributed Id using UUID.randomUUID().

To acquire the locks, issue an update to try to grab it, and then query it to see if you have the lock. But don't do select, check and then update. Locks older than a certain amount of time should be not taken into account.

This is an implementation of to the coarse grained lock design pattern, where an application level pessimistic lock is acquired to lock shared resources.

Depending on the business logic on the services and the type of transaction manager you use, increasing the isolation level of the service method to REPEATABLE_READ might be an option.

For a solution that does not involve the database, have a look at a framework for distributed concurrent processing based on the Actor concurrency model - The Akka Framework (click Remoting button).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top