javamultithreadingexceptionparallel-processingillegalmonitorstateexcep

Can anybody explain why this program is showing an IllegalMonitorStateException?


class Lock 
{
    public int l=0;
}

class Numbers extends Thread
{
    final Lock lock;
    Numbers(Lock l,String name)
    {
        super(name);
        lock=l;
    }
    
    public void run()
    {
        synchronized(lock)
        {
            for(int i=0;i<100;i++)
            {
                if(i==50)
                {
                    try
                    {
                        while(lock.l==0)
                        {
                            System.out.println("Waiting for letters to complete");
                            wait();
                            System.out.println("Wait complete");
                        }
                    }
                    catch(InterruptedException e)
                    {
                        System.err.println("ERROR");
                    }
                }
                System.out.println(i);
            }
        }
    }
}

class Letters extends Thread
{
    final Lock lock;
    Letters(Lock l,String name)
    {
        super(name);
        lock=l;
    }
    
    public void run()
    {
        synchronized(lock)
        {
            for(int i=65;i<=90;i++)
                System.out.println((char)i);
            lock.l=1;
            notify();
        }
    }
}

public class MyClass
{
    public static void main(String args[])
    {
        Lock l=new Lock();
        Numbers n=new Numbers(l,"Numbers");
        Letters let=new Letters(l,"Letters");
        n.start();
        let.start();
    }
}

What I intend through this program is to print the numbers up to 49 and then wait till the Letters thread finishes printing letters and then the control goes back to Numbers thread and finishes execution.

But this code throws exception after printing numbers up to 49 then prints A-Z and then fails to execute showing IllegalMonitorStateException.


Solution

  • fails to execute showing IllegalMonitorStateException.

    This results from the fact that the call to the notify(); method is not obeying to the its contract:

    Wakes up a single thread that is waiting on this object's monitor. (...) This method should only be called by a thread that is the owner of this object's monitor.

    and the same applies for the wait method:

    This method should only be called by a thread that is the owner of this object's monitor.

    TL:DR

    You are calling wait and notify() on the wrong lock (i.e., the implicit lock of the instance return by this).

    Change, respectively, those calls to:

    lock.notify(); and lock.wait();

    Running Example based on your code:

    class Lock{
        public int l=0;
    }
    
    class Numbers extends Thread
    {
        final Lock lock;
        Numbers(Lock l,String name){
            super(name);
            lock=l;
        }
    
        public void run() {
            synchronized(lock) {
                for(int i=0;i<100;i++){
                    if(i==50){
                        try {
                            while(lock.l==0){
                                System.out.println("Waiting for letters to complete");
                                lock.wait();
                                System.out.println("Wait complete");
                            }
                        }
                        catch(InterruptedException e){
                            System.err.println("ERROR");
                        }
                    }
                    System.out.println(i);
                }
            }
        }
    }
    
    class Letters extends Thread {
        final Lock lock;
        Letters(Lock l,String name)
        {
            super(name);
            lock=l;
        }
    
        public void run()
        {
            synchronized(lock){
                for(int i=65;i<=90;i++)
                    System.out.println((char)i);
                lock.l=1;
                lock.notify();
            }
        }
    }
    
    class MyClass {
        public static void main(String args[]) {
            Lock l=new Lock();
            Numbers n=new Numbers(l,"Numbers");
            Letters let=new Letters(l,"Letters");
            n.start();
            let.start();
        }
    }