reason of IllegalMonitorStateException if I use wait within sync block

10,928

Solution 1

You are synchronizing on monitor, so you should wait() on monitor, too:

monitor.wait();

Right now you are waiting on this, which is not the owner of the monitor because synchronization is on monitor.

Note that of course the notify should also be done on the monitor object, and that you might want to consider using notify/notifyAll in both threads. Otherwise it may happen that one thread starves waiting for a missing notification. Using a timeout (the overloaded version of wait) might also be a good idea to catch corner cases.

Solution 2

The reason - The current thread is not the owner of the object's monitor.To call wait() method the current thread must own this object's monitor.
In your case you are obtaining monitor on monitor object instead current object(this object).

Share:
10,928
gstackoverflow
Author by

gstackoverflow

Updated on June 04, 2022

Comments

  • gstackoverflow
    gstackoverflow almost 2 years

    I try to understand java core synchronization.

    I wrote code sample:

    Program should write

    left right

    10 times

    package concurrency;
    
    public class LeftRightWaitNotifyExample {
        final static String str = "1";
    
        public static void main(String[] args) {
    
            new LeftLegThread(str).start();
            new RightLegThread(str).start();
        }
    }
    
    class LeftLegThread extends Thread {
        String monitor;
    
        public LeftLegThread(String str) {
            monitor = str;
        }
    
        @Override
        public void run() {
            try {
                makeStep();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        private void makeStep() throws InterruptedException {
            synchronized (monitor) {
    
                for (int i = 0; i < 10; i++) {
                    System.out.println("Left ");
                    wait();
                }
            }
        }
    }
    
    class RightLegThread extends Thread {
        String monitor;
    
        public RightLegThread(String str) {
            monitor = str;
        }
    
        @Override
        public void run() {
            try {
                makeStep();
            } catch (InterruptedException e) {
    
            }
        }
    
        private void makeStep() throws InterruptedException {
            synchronized (monitor) {
                while (true) {
                    System.out.println("Right ");
                    notify();
                    wait();
                }
            }
        }
    }
    

    I get this output:

    Left 
    Right 
    Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:485)
        at concurrency.LeftLegThread.makeStep(LeftRightWaitNotifyExample.java:35)
        at concurrency.LeftLegThread.run(LeftRightWaitNotifyExample.java:23)
    Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
        at java.lang.Object.notify(Native Method)
        at concurrency.RightLegThread.makeStep(LeftRightWaitNotifyExample.java:61)
        at concurrency.RightLegThread.run(LeftRightWaitNotifyExample.java:51)
    

    Before I got this error when I used wait method non within synchronized block. But here I use wait within synchronized block

    What is the cause of the problem and how to fix it?

    update

    I rewrite code according advice:

    public class LeftRightWaitNotifyExample {
        final static String str = "1";
    
        public static void main(String[] args) throws InterruptedException {
    
            new LeftLegThread(str).start();
            Thread.sleep(100);
            new RightLegThread(str).start();
        }
    }
    
    class LeftLegThread extends Thread {
        String monitor;
    
        public LeftLegThread(String str) {
            monitor = str;
        }
    
        @Override
        public void run() {
            try {
                makeStep();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        private void makeStep() throws InterruptedException {
            synchronized (monitor) {
    
                for (int i = 0; i < 2; i++) {
                    System.out.println("Left ");
                    monitor.wait();
                    monitor.notify();
                }
            }
        }
    }
    
    class RightLegThread extends Thread {
        String monitor;
    
        public RightLegThread(String str) {
            monitor = str;
        }
        @Override
        public void run() {
            try {
                makeStep();
            } catch (InterruptedException e) {
    
            }
        }
    
        private void makeStep() throws InterruptedException {
            synchronized (monitor) {
                while (true) {
                    System.out.println("Right ");
                    monitor.notify();
                    monitor.wait();
                }
            }
        }
    }
    

    current output:

    Left 
    Right 
    Left 
    Right 
    Right 
    

    Why does Right outs 3 but Left only twice. Why?

  • gstackoverflow
    gstackoverflow about 10 years
    I have misunderstanding. I can use wait only on synchronized(this) ?
  • gstackoverflow
    gstackoverflow about 10 years
    really. amazing. But after replacing I see **Left Right Left ** and program is freezes
  • Prabhaker A
    Prabhaker A about 10 years
    @gstackoverflow No you can use any object but the rule is you have to call wait() method on object which is synchronized.