如果我在同步块中使用wait,则出现IllegalMonitorStateException的原因

时间:2014-04-22 08:56:06

标签: java concurrency synchronization wait

我尝试了解java核心同步。

我写了代码示例:

程序应该写

  

左   右

10次

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();
            }
        }
    }
}

我得到了这个输出:

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)

当我在wait块中使用synchronized方法时出现此错误之前。但是我在synchronized块中使用等待

问题的原因是什么以及如何解决?

更新

我根据建议改写代码:

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();
            }
        }
    }
}

当前输出:

Left 
Right 
Left 
Right 
Right 

为什么Right只有3,但Left只有两次。为什么呢?

4 个答案:

答案 0 :(得分:5)

您正在monitor进行同步,所以您应该wait()在监视器上:

monitor.wait();

现在您正在等待this,这不是监视器的所有者,因为同步在monitor上。

请注意,当然notify也应该在monitor对象上完成,并且您可能要考虑在中使用notify / notifyAll 线程。否则可能会发生一个线程饿死等待丢失通知。使用超时(wait的重载版本)也可能是捕捉极端情况的好主意。

答案 1 :(得分:0)

原因 - The current thread is not the owner of the object's monitor。要调用wait()方法,当前线程必须拥有此对象的监视器。
在您的情况下,您将获得monitor对象上的监视器而不是当前对象(此对象)。

答案 2 :(得分:0)

您正在尝试锁定监视器对象。但它是锁定线程对象(LeftLegThread,RightLegThread)。实际上它并未锁定同步。

monitor.wait();将会解决。

答案 3 :(得分:0)

public class LeftRightWaitNotifyExample {
    final static String str = "1";

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

        new LeftLegThread(str).start();
        Thread.sleep(1000);
        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) {
            e.printStackTrace();
        }
    }

    private void makeStep() throws InterruptedException {
        synchronized (monitor) {

            while (true) {
                System.out.println("Left ");
                monitor.wait();
                monitor.notify();
                Thread.sleep(1000);
            }
        }
    }
}

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();
                Thread.sleep(1000);
            }
        }
    }
}