【问题标题】:reason of IllegalMonitorStateException if I use wait within sync block如果我在同步块中使用等待,则会出现 IllegalMonitorStateException 的原因
【发布时间】:2014-04-22 08:56:05
【问题描述】:

我尝试了解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)

当我在synchronized 块中使用非wait 方法时收到此错误之前。但这里我在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 只输出两次。为什么?

【问题讨论】:

    标签: java concurrency synchronization wait


    【解决方案1】:

    你在monitor上同步,所以你也应该在监视器上wait()

    monitor.wait();
    

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

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

    【讨论】:

    • 真的。惊人的。但是替换后我看到 **Left Right Left ** 并且程序冻结了
    【解决方案2】:

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

    【讨论】:

    • 我有误会。我只能在 synchronized(this) 上使用等待?
    • @gstackoverflow 不,您可以使用任何对象,但规则是 you have to call wait() method on object which is synchronized
    【解决方案3】:

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

    monitor.wait();会解决的。

    【讨论】:

      【解决方案4】:
      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);
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2023-03-13
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-01
        • 2011-09-12
        • 2020-07-11
        相关资源
        最近更新 更多