Search code examples
javaconcurrencysynchronizationwait

reason of IllegalMonitorStateException if I use wait within sync block


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?


Solution

  • 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.