user3302709
user3302709

Reputation: 1038

Name based Reentrant Lock in Java

my problem is I want a user based lock that I am able to create in one thread and release in a different thread. I was trying to use reetrant locks but my idea is falling short somewhere.

I.e. There are blue, green and purple people. Each color group only has one shovel. If the purple group needs to use the shovel they need to wait for the shovel to be available. Both the blue group and purple group can have their respective shovels at a given moment.

Mainclass

public class MainReentrant {

    public static ConcurrentHashMap<String, ReentrantLock> locks;

    public static void main(String[] args){

            locks = new ConcurrentHashMap<String, ReentrantLock>();

            new Thread( new ReentrantEx(1)).start();;
            new Thread( new ReentrantEx(1)).start();;
            new Thread( new ReentrantEx(2)).start();;

    }
}

The first step is to create a lock and lock it.

public class ReentrantEx implements Runnable {
    private Integer id;

    public ReentrantEx(Integer id){
        this.id = id;
    }
    public void doSomethingPerUser(Integer i){
        synchronized(i){
            ReentrantLock tempLock = MainReentrant.locks.get(i.toString());

            if(tempLock != null){
                //we have an unlocked lock
                tempLock.lock();
            }else{
                //add a new lock for this customer
                tempLock = new ReentrantLock();
                tempLock.lock();
                MainReentrant.locks.put(i.toString(), tempLock);
            }

            System.out.println("doSomethingPerUser lock should be held : " + i);

            new Thread(new RandomRunnable(i)).start();

        }
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        doSomethingPerUser(id);

    }
}

next the randomRunnable class attempts to release the lock created by ReentrantEx

public class RandomRunnable implements Runnable {

    private Integer id; 
    public RandomRunnable(Integer id){
        this.id = id;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        System.out.println(" RandomRunnable: id = "+ id );

        ReentrantLock tempLock = MainReentrant.locks.get(id.toString());

        synchronized(tempLock){
            if(tempLock == null){
                System.out.println("ERROR: we have a lock that we cannot free");
                return;
            }else{
                tempLock.unlock();
                //ReentrantEx.locks.put(id.toString(), tempLock);
            }
        }
    }

}  

Whenever I do this I get these sort of errors:

Exception in thread "Thread-5" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:127)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1239)
    at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:431)
    at test.RandomRunnable.run(RandomRunnable.java:25)
    at java.lang.Thread.run(Thread.java:695)       

here is a good link on the locks in general... locks

Upvotes: 1

Views: 1519

Answers (1)

Marko Topolnik
Marko Topolnik

Reputation: 200296

Simply put, ReentrantLock is not for you. The subject acquring the lock is a thread, so when you attempt to release it in another thread, that thread is actually trying to release a lock it doesn't own. Meanwhile the thread that did acquire it, keeps holding on to it.

What you probably need instead is a Semaphore—more specifically, a collection of semaphores, one for each color group.

Upvotes: 4

Related Questions