Ajay
Ajay

Reputation: 3086

IlleagalMonitorStateException when I am trying to run this program

public class ThreadTest
{
 public static Integer i = new Integer(0);

 public static void main(String[] args) throws InterruptedException
 {
  ThreadTest threadTest = new ThreadTest();
  Runnable odd = threadTest.new Numbers(1, "thread1");
  Runnable even = threadTest.new Numbers(0, "thread2");
  ((Thread) odd).start();
  ((Thread) even).start();
 }

 class Numbers extends Thread
 {
  int reminder;
  String threadName;

  Numbers(int reminder, String threadName)
  {
   this.reminder = reminder;
   this.threadName = threadName;
  }

  @Override
  public void run()
  {
   while (i < 20)
   {
    synchronized (i)
    {
     if (i % 2 == reminder)
     {
      System.out.println(threadName + " : " + i);
      i++;
      i.notify();
     }
     else
     {
      try
      {
       i.wait();
      }
      catch (InterruptedException e)
      {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
     }
    }
   }
  }
 }
}

Upvotes: 1

Views: 134

Answers (4)

SimonJ
SimonJ

Reputation: 21306

This line:

i++;

is equivalent to:

i = i + 1;

which (due to autoboxing) becomes something like:

i = new Integer(i.intValue() + 1);

So, when you call i.notify() you are synchronized on the old i, not the new one.

I'd suggest changing i into an ordinary int variable, and create a separate object to synchronize on:

static int i = 0;
static Object iMonitor = new Object();

Upvotes: 1

axtavt
axtavt

Reputation: 242686

You can't synchronize on i because it changes during execution of your program.

Since Integer in Java is immutable, after executing i++ i will contain a reference to another object, not the object you have synchronized on. So, you can't call wait()/notify() on this new object, because these methods may be only called on the object you are synchronized on, otherwise you get IllegalMonitorStateException.

You need to synchronize on some other object that doesn't change during execution. For example, you may create a separate object for this purpose:

public class ThreadTest { 
    public static Integer i = new Integer(0); 
    public static Object lock = new Object();
    ...
    class Numbers extends Thread { 
        ...
        @Override 
        public void run() { 
             ...
             synchronized (lock) {
                 ...
                 lock.notify();
                 ...
                 lock.wait();
                 ...
             }
        }
    }
}

Upvotes: 3

Anand
Anand

Reputation: 729

You cannot put wait() and notify() in the same synchronized block because that will just cause a deadlock. Make sure only the wait and notify functions are wrapped with a synchronized block like this:

synchronized (i) {
    i.wait(); // or i.notify();
}

Upvotes: -1

Jack
Jack

Reputation: 133577

As documentation states the exception is thrown when

the current thread is not the owner of the object's monitor

It also states that

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

And this condition can be obtained by

  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.

You could try calling the wait method from inside the class that uses i. This could be done by extending the class and writing two new methods for notify and wait..

Upvotes: 0

Related Questions