Wei JingNing
Wei JingNing

Reputation: 251

IllegalMonitorStateException with two threads

My program has two Threads, each prints ten numbers. The first Thread prints the odd number, the second Thread prints the even number, and they take turns printing numbers. I'm expecting to get a sequence like 1,2,3,4,5....until 20, but the program produces an IllegalMonitorStateException.

I know what this Exception means, but I use wait() and notify() in the synchronized block. Here is my code:

     public class EvenOddThreadTest {

      /**
       * @param args
       */
      static Object obj1 = new Object();
      static Object obj2 = new Object();
      static Object obj3=new EvenOddThreadTest();

      public static void main(String[] args) throws InterruptedException {
          new Thread() {
              @Override
              public void run() {

                      for (int i = 1; i < 21; i += 2) {
                          synchronized (obj1) {
                          System.out.println(i + Thread.currentThread().getName());
                          try {
                              obj2.notify();                    
                              obj1.wait();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }

                      }
                  }
              }
          }.start();
          new Thread() {
              @Override
              public void run() {
                      for (int i = 2; i < 21; i += 2) {
                          synchronized (obj2) {

                          System.out.println(i + Thread.currentThread().getName());
                        try {
                            obj1.notify();
                            obj2.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            }.start();
        }
    }

and this is the Exception generated:

1Thread-0
2Thread-1
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at EvenOddThreadTest$1.run(EvenOddThreadTest.java:21)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at EvenOddThreadTest$2.run(EvenOddThreadTest.java:41)

I can't figure this out. Any ideas?

Upvotes: 0

Views: 16471

Answers (4)

Michael Krussel
Michael Krussel

Reputation: 2656

Both threads need to synchronize on the same variable, if they are working together. What you want is for one to wait for its turn to run, then run, then notify the other thread.

public class EvenOddThreadTest {

  /**
   * @param args
   */
  static Object obj1 = new Object();
  static Object obj3=new EvenOddThreadTest();

  public static void main(String[] args) throws InterruptedException {
      new Thread() {
          @Override
          public void run() {

                  for (int i = 1; i < 21; i += 2) {
                      synchronized (obj1) {
                      try {
                          while (/* not my turn to run *?*/) {                   
                             obj1.wait();
                          }
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(i + Thread.currentThread().getName());
                      obj1.notify();
                  }
              }
          }
      }.start();
      new Thread() {
          @Override
          public void run() {
                  for (int i = 2; i < 21; i += 2) {
                      synchronized (obj1) {
                      try {
                          while (/* not my turn to run *?*/) {                   
                             obj1.wait();
                          }
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(i + Thread.currentThread().getName());
                      obj1.notify();
                }
            }
        }

        }.start();
    }
}

Upvotes: 4

assylias
assylias

Reputation: 328608

This does not answer your question directly but Threads are quite low level. In your case, you could for example use a CyclicBarrier, which will handle the synchronization details for you:

public class Test {

    static CyclicBarrier barrier = new CyclicBarrier(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread() {

            @Override
            public void run() {
                try {
                    for (int i = 1; i < 21; i += 2) {
                        System.out.println(i + Thread.currentThread().getName());
                        barrier.await();
                    }
                } catch (BrokenBarrierException e) {
                    //do something
                } catch (InterruptedException e) {
                    //do something
                }
            }
        }.start();
        new Thread() {

            @Override
            public void run() {
                try {
                    for (int i = 2; i < 21; i += 2) {
                        barrier.await();
                        System.out.println(i + Thread.currentThread().getName());
                    }
                } catch (BrokenBarrierException e) {
                    //do something
                } catch (InterruptedException e) {
                    //do something
                }
            }
        }.start();
    }
}

Upvotes: 0

Marc-Christian Schulze
Marc-Christian Schulze

Reputation: 3254

In thread 0 you are only synchronizing on the obj2 not obj1 on which you invoke notify. In the second thread it's the other way around.

Upvotes: 1

artbristol
artbristol

Reputation: 32407

You can't call notify on an object whose monitor you don't own:

               synchronized (obj1) {
                  System.out.println(i + Thread.currentThread().getName());
                  try {
                      obj2.notify();  // You haven't synchronized on obj2 

Upvotes: 7

Related Questions