We sorted this issue out differently, with a high performance impact, using an ordinary lock which will be a bottleneck under some scenarios. But I managed to get a solution, not tested though. This consists of a Lock class which contains a pool of Locks and provides them to threads according a termId. All threads who share the same termId will be provided with the same Lock. This way we'll get all threads grouped by termId, all lined up in different queues. I set a fixed pool of locks, though I think it could be dynamic also,removing and adding Locks on demand.
Any feedback will be appreciated
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
public class Lock {
private Lock() {}
private static class SingletonHolder {
/** ordered list. Locks with termId null must be at the end **/
public static final ArrayList<Lock> INSTANCES = new ArrayList<Lock>(){{
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
add(new Lock());
}};
public static synchronized Lock returnInstance(String termId){
ArrayList<Lock> sortedList = sortInstances();
for(Lock instance: sortedList){
if(termId.equals(instance.getTermId()))
return instance;
if(instance.getTermId()==null)
return instance;
}
return null;
}
public static ArrayList<Lock> sortInstances(){
ArrayList<Lock> sortedList=new ArrayList<Lock>();
for(Lock instance: INSTANCES){
if(instance.getTermId()==null)
sortedList.add(instance);
else
sortedList.add(0,instance);
}
return sortedList;
}
}
/**
* Use this method to get a reference to a singleton instance of
* {@link Lock}
*
* @return a singleton instance
*/
public static Lock getInstance(String termId) {
return SingletonHolder.returnInstance(termId);
}
private Semaphore lock = new Semaphore(1);
private String termId;
public void getLock(String termId) throws InterruptedException {
lock.acquire();
setTermId(termId);
}
public void releaseLock() {
lock.release();
setTermId(null);
}
public String getTermId() {
return termId;
}
public void setTermId(String termId) {
this.termId = termId;
}
}