javaconditional-statementsillegalmonitorstateexcep

IllegalMonitorStateException with Condition


So I'm trying to write a program that prints out the following output:

44
33
22
11

The program is supposed to be multithreaded and must use locks in order to prevent race conditions. It must also make use of Condition so that when the number a thread wants to print doesn't correspond with variable threadnum (the next number that has to be printed), it has to wait. I've gotten most of it except I'm getting IllegalMonitorStateExceptions when I try to run it and I'm not sure what's causing it, nor how to fix it. I would appreciate some help. Thanks in advance.

public class Threadlocksrev implements Runnable {
Lock lock = new ReentrantLock();
Condition wrongNumber = lock.newCondition();
int i;
static int threadnum = 4;

public Threadlocksrev(int i){
    this.i = i;
}

private int getI(){
    return i;
}

@Override
public synchronized void run() {
    lock.lock();
    while(true){
        if (threadnum == i){
            try{
                System.out.print(getI());
                System.out.print(getI());
                System.out.print("\n");
                threadnum--;
                wrongNumber.signalAll();
            }
            catch(Exception e){
                e.printStackTrace();
            }
            finally{

                lock.unlock();
            }
        }
            else{
                try {
                    wrongNumber.await();
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally{
                    wrongNumber.signalAll();
                    lock.unlock();
                }
            }


        }
    }
}

The main class:

public class ThreadlocksrevInit {

private static final int max_threads = 4;

public static void main(String[] args) {
    Threadlocksrev task1 = new Threadlocksrev(1);
    Threadlocksrev task2 = new Threadlocksrev(2);
    Threadlocksrev task3 = new Threadlocksrev(3);
    Threadlocksrev task4 = new Threadlocksrev(4);
    Thread thread1 = new Thread(task1);
    Thread thread2 = new Thread(task2);
    Thread thread3 = new Thread(task3);
    Thread thread4 = new Thread(task4);

    thread1.start();
    thread2.start();
    thread3.start();
    thread4.start();
    }

}

Solution

  • You are busy spinning in the same thread, attempting to unlock over and over again, which when the calling thread does not own the lock causes your illegal monitor state exception. In this code:

    if (threadnum == i){
    

    You are comparing a static variable to the index of the thread. Because the static variable will be the same value (after all the threads are setup), you are only invoking the while loop for the one, same thread. All the others are just blocked. And because you do this:

    lock.lock();
    

    Outside of the while loop, the sole running thread only executes correctly the first time (aka when it had the lock). In all other iterations of the loop it does not have a valid lock, so when it calls:

    finally{
        lock.unlock();
    }
    

    You get your illegal monitor state exception.