Michael_user3015308 Michael_user3015308 - 1 year ago 64
Java Question

Lock is lost when putting ReentrantLock into HashMap

I am trying to make several consumer threads that listen to one producer thread wait until the producer has something to publish. The code that I thought would work "loses" the lock on being put into and taken out of a shared class.

In a controller class I start the thread running with
Server server = new Server();

Thread serverThread = new Thread(server,"Server");

Consumer consumer = new Consumer();
Thread consumerThread;
for (int i =0;i<6;i++){
consumerThread = new Thread(consumer,"Consumer No:"+i);
server.threadRefs[i]= consumerThread;

The consumer classes put details of threads into the Map as follows:

public class Consumer implements Runnable {

private ReentrantLock lock = new ReentrantLock();
private Condition cond = lock.newCondition();

public void run() {

long threadID = Thread.currentThread().getId();
while (true) {
try {


MDRequest.threadLocks.put(threadID, lock);
System.out.println("Thread " + threadID + " lock = " + lock.toString());

System.out.println("Thread " + threadID + " done waiting");
} catch (InterruptedException ex) {
System.out.println("Interruped " + threadID);
} finally {

System.out.println("Finished " + threadID);


The shared class is simply:

public class MDRequest {

protected static ConcurrentHashMap<Long, ReentrantLock> threadLocks = new ConcurrentHashMap<Long, ReentrantLock>();

The Server has the following run() method:

public void run() {
try {
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
Set<Long> keys = MDRequest.threadLocks.keySet();
Long[] threadIDs = keys.toArray(new Long[1]);

// generates a random series of numbers for each thread and notifies threads about them
while (true) {

Random random = new Random();
int threadRef = random.nextInt(5);

System.out.println("About to signal thread " + threadIDs[threadRef].toString());

// notify the thread of the data
ReentrantLock lock = MDRequest.threadLocks.get(threadIDs[threadRef]);
System.out.println("Thread " + threadIDs[threadRef].toString() + " lock = " + lock.toString());

Condition cond = lock.newCondition();


The output is as follows:

Thread 11 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:0]
Thread 12 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:1]
Thread 13 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:2]
Thread 14 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:3]
Thread 15 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:4]
Thread 16 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Locked by thread Consumer No:5]
About to signal thread 14
Thread 14 lock = java.util.concurrent.locks.ReentrantLock@272d7a10[Unlocked]
Exception in thread "Price Server" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1885)
at faster.Server.run(Server.java:46)
at java.lang.Thread.run(Thread.java:695)

From the output int the Server class I can see that when I read the lock out of the Map it now has a status of "Unlocked". When it was put in it had a status of Locked on thread 14.

Why does the reference to the ReentrantLock "lose" the lock?

Is there a way of sharing the lock between the multiple consumer threads and the server thread in a way that the lock is not lost?

Answer Source

The problem is thread in Server class tries to unlock but has not lock the Lock


Please see ReentrantLock documentation where is clearly stated:

If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download