简体   繁体   English

为什么这会引发IllegalMonitorStateException?

[英]Why does this throw an IllegalMonitorStateException?

I am getting into Java multithreading. 我正在学习Java多线程。 I am very familiar with C/C++ pthreads, but am having issues with the Java notify() and wait() functions. 我对C / C ++ pthread非常熟悉,但是Java的notify()wait()函数存在问题。

I understand that an IllegalMoinitorStateException is only thrown when a thread that doesnt "own" (aka hasnt synchronized) calls notify/wait. 我了解,仅当不“拥有”(也称为“未同步”)的线程调用通知/等待时,才会引发IllegalMoinitorStateException

When writing my application, I ran into this issue. 在编写应用程序时,我遇到了这个问题。 I isolated the problem with the following test code: 我使用以下测试代码隔离了该问题:

public class HelloWorld
{
    public static Integer notifier = 0;
    public static void main(String[] args){
        notifier = 100;
        Thread thread = new Thread(new Runnable(){
            public void run(){
                    synchronized (notifier){
                            System.out.println("Notifier is: " + notifier + " waiting");
                            try{
                                notifier.wait();
                                System.out.println("Awake, notifier is " + notifier);
                            }
                            catch (InterruptedException e){e.printStackTrace();}
                    }
            }});
        thread.start();
        try{
                Thread.sleep(1000);
            }
        catch (InterruptedException e){
                e.printStackTrace();
            }
        synchronized (notifier){
            notifier = 50;
            System.out.println("Notifier is: " + notifier + " notifying");
            notifier.notify();
        }
        }
    }

This outputs: 输出:

    Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notify(Native Method)
        at HelloWorld.main(HelloWorld.java:27)

I believe I have already acquired the lock on the notifier object. 我相信我已经获得了通知程序对象的锁定。 What am I doing wrong? 我究竟做错了什么?

Thanks! 谢谢!

EDIT: 编辑:

From this possible duplicate( Synchronizing on an Integer value ), it seems that it is not a good idea to synchronize on an Integer because it is hard to make sure you are synchronizing on the same instance. 从这个可能的重复项( 在Integer值上同步 )看来,在Integer上同步并不是一个好主意,因为很难确保您在同一实例上进行同步。 Since my integer I am synchronizing on is a global visibile static integer, why am I getting different instances? 由于我要同步的整数是全局可见的静态整数,为什么会得到不同的实例?

Because of notifier = 50; 因为notifier = 50; you are calling notifier.notify(); 您正在调用notifier.notify(); on a different object. 在另一个对象上。

Initially when you calling synchronized on notifier in non-main Thread it was referencing to the object on heap whose content was 0 hence the thread owns that object . 最初,当您在非主线程中的notifier上调用synchronized时,它引用的是内容为0堆上的对象,因此线程拥有该对象。 Now after non-main thread is put on wait using notifier.wait the control is given to the main thread . 现在,使用notifier.wait将非主线程置于wait将控制权交给主线程。 There after acquiring lock on object of Integer containing value 0 you made the notifier to refer the other object on heap memory containing value 50 because notifier = 50; 在获得对包含值0的Integer对象的锁定之后,您使notifier程序引用包含值50堆存储器上的另一个对象,因为notifier = 50; is actually equivalent to notifier = new Integer(50) which means a new object of Integer is created and its reference is passed to notifier . 实际上等效于notifier = new Integer(50) ,这意味着将创建一个Integer的新对象,并将其引用传递给notifier Now , when the thread sees notifier.notify it looks that the Main thread now no longer owns the original object that it had acquired before. 现在,当线程看到notifier.notify它看起来像是Main线程现在不再拥有它之前获取的原始对象。 So IllegalMonitorStateException is throwing. 因此,抛出IllegalMonitorStateException

Just to add more information, you should never synchronize on a non-final object. 仅添加更多信息,就永远不要在非最终对象上进行同步。

You need to synchronize on a constant object. 您需要在一个常量对象上进行同步。 If you synchronized on any object that you are assigning (ie changing the object) then the object is not constant and once it assigns the object and tries to notify on it, you will get the IllegalMonitorStateException . 如果您在要分配的任何对象上进行同步(即更改对象),则该对象不是恒定的,并且一旦分配了对象并尝试对其进行通知,您将获得IllegalMonitorStateException It also means that because they are synchronizing on different objects, multiple threads will be entering the protected block at the same time and race conditions will happen. 这也意味着,由于它们正在不同的对象上进行同步,因此多个线程将同时进入受保护的块,并且会发生竞争状况。

Since my integer I am synchronizing on is a global visibile static integer, why am I getting different instances? 由于我要同步的整数是全局可见的静态整数,为什么会得到不同的实例?

When you assign a value to an Integer it changes it to a different object reference -- even if it is static . 将值分配给Integer ,即使它是static它也会将其更改为其他对象引用。 You are not changing the same object because Integer can't be mutated. 不会更改同一对象,因为不能对Integer进行突变。 So notifier = 50; notifier = 50; assigns it to a different object than notifier = 0; 将其分配给notifier = 0;以外的其他对象notifier = 0; .

If you want to use, for example, a constant object you can use an AtomicBoolean : 例如,如果要使用常量对象,则可以使用AtomicBoolean

  public static final AtomicInteger notifier = new AtomicInteger(0);
  ...
  synchronize (notifier) {
      notifier.set(50);
      ...
  }

Here, AtomicInteger can be marked final because it's the same object all of the time. 在这里,可以将AtomicInteger标记为final因为它始终都是同一对象。

For more information, see: Why is it not a good practice to synchronize on Boolean? 有关更多信息,请参见: 为什么在Boolean上同步不是一个好习惯?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么此代码会引发IllegalMonitorStateException? - why does this code throw a IllegalMonitorStateException? 为什么 JMockit 期望阻塞会抛出 IllegalMonitorStateException? - Why does JMockit expectations block throws IllegalMonitorStateException? 此代码可以引发IllegalMonitorStateException - This Code can Throw an IllegalMonitorStateException 有谁知道为什么我得到这个IllegalMonitorStateException? - Does anyone know why I am getting this IllegalMonitorStateException? 为什么notifyAll()在Integer上同步时会引发IllegalMonitorStateException? - Why does notifyAll() raise IllegalMonitorStateException when synchronized on Integer? 当我以静态方式同步块调用wait()时,为什么Java会抛出java.lang.IllegalMonitorStateException? - Why Java throw java.lang.IllegalMonitorStateException when I invoke wait() in static way synchronized block? libgdx iOS httpUrlConnection.connect抛出IllegalMonitorStateException - libgdx iOS httpUrlConnection.connect throw IllegalMonitorStateException 为什么这会引发InputMismatchException? - Why does this throw a InputMismatchException? 为什么会抛出OOM? - Why does it throw OOM? 为什么这会引发NullPointerException? - Why does this throw a NullPointerException?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM