-1

This is my first post so sorry if I do something wrong. I'm trying to understand how work the threads in Java, in particular the synchronization, that's why I created a little piece of code which is supposed to print 1, 2, 3, 4, 5, 6 (in one thread) and then a second thread wait that's the first finished and then print 6, 5, 4, 3, 2, 1 but it only do the first 6 steps and tell me that there is a monitor problem for the wait method in the thread t2 and a problem with the notify all of the thread t1. Maybe I haven't understood anything about the synchronization of an object. Here is my code :

public class anObject extends Thread {

long value;
String name;

public anObject(long value, String name) {
    this.value = value;
    this.name = name;
}

public synchronized void add() {
    this.value++;
}

public synchronized void sub() {
    this.value--;
}

public static void main(String[] args) {

    anObject il = new anObject(0, "Bob");

    synchronized (il) {

        Thread t1 = new Thread(il) {
            public void run() {
                while (il.value > 0) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                for (int i = 0; i < 6; i++) {
                    il.add();
                    System.out.println(il.value);
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                il.notifyAll();
            }
        };

        Thread t2 = new Thread(il) {
            public void run() {
                while (il.value < 6) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                for (int j = 0; j < 6; j++) {
                    il.sub();
                    System.out.println(il.value);
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                il.notifyAll();
            }
        };

        t1.start();
        t2.start();

    }
}

}

And this is what appeared in the terminal :

Exception in thread "Thread-2" 1
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at anObject$2.run(anObject.java:53)
2
3
4
5
6
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at anObject$1.run(anObject.java:45)

Thanks a lot for your help! Greetings

Kent
  • 3
  • 4

2 Answers2

0

What you are doing by this

synchronized (il)

is just grabbing an object's monitor from the main thread. But inside you are initializing two new threads and trying to call the wait() method from the contexts of both of these recently initialized and then started threads. The main idea of IllegalMonitorStateException is that you are trying to call a method that uses a context of object's locking without preceding obtaining of this object's lock. What you can do to fix it fast is just to change

while (il.value > 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

on

while (il.value > 0) {
                try {
                    synchronized(this) {
                        this.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

and to make an equal change in the second block of code. But to really make it right, I would recommend you to turn to some strong sources describing multithreading concept. Oracle's basic java tutorial will be just fine I suppose.

nyarian
  • 4,085
  • 1
  • 19
  • 51
0

wait is defined in Object, this is why you get this exceptions.

I prefer dedicated lock for avoid the unpredictable monitor exceptions:

private final Object lock = new Object();


private static final class Lock { }
private final Object lock = new Lock();

For notify or notifyAll an object, you need to be holding the lock with the synchronized statement. Also, you should define a loop to check for the wakeup condition.

synchronized (lock) {
    while (!isWakeupNeeded()) {
        lock.wait();
    }
}

To notify:

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}
Ugur Tufekci
  • 350
  • 2
  • 13
  • So you suggest that I create an instance of Object named lock and I synchronized it in my thread instead of synchronize the this Object ? – Kent Mar 08 '18 at 08:37