2013-03-23 99 views
2

我正在进入Java多线程。我对C/C++ pthreads非常熟悉,但是遇到了Java notify()wait()函数的问题。为什么会抛出IllegalMonitorStateException?

据我所知,IllegalMoinitorStateException只有当一个线程不“拥有”(又名未经同步)调用通知/等待。

当写我的申请,我就遇到了这个问题。我分离下面的测试代码的问题:

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

此输出:

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

相信我已经获取的通知对象的锁。我究竟做错了什么?

谢谢!

编辑:

从这个可能重复(Synchronizing on an Integer value),它似乎不是在整型同步,因为这是很难确保你是在同一个实例进行同步是个好主意。因为我正在同步的整数是全局可见的静态整数,为什么我得到不同的实例?

+0

可能重复:HTTP://stackoverflow.com/questions/659915/synchronizing-on-an-integer-value – Cratylus 2013-03-23 19:26:59

+0

又一个暗示,因为它已经有了答案:尝试将通知设置为最终。由于您为通知程序指定了不同的值(对象),因此它不会编译。 – 2013-03-23 20:07:11

回答

5

由于notifier = 50;要调用不同的对象上notifier.notify();

0

最初,当您在非主线程中调用同步notifier时,它引用堆中的对象,其内容为0,因此线程拥有该对象。现在,在使用notifier.wait将非主线程放在wait后,控制权交给了主线程。在获取包含值0的Integer对象的锁之后,您使notifier引用包含值50的堆内存上的另一个对象,因为notifier = 50;实际上等于notifier = new Integer(50),这意味着将创建一个新对象Integer并将其参考传递给notifier。现在,当线程看到notifier.notify时,它看起来主线程现在不再拥有它之前获得的原始对象。所以IllegalMonitorStateException正在抛出。

0

只需添加更多的信息,你不应该在非最终目标上同步。

你需要一个恒定对象上同步。如果您正在分配(即改变物体)的任何对象上同步,则对象不是恒定的,一旦分配对象,并设法通知它,你会得到IllegalMonitorStateException。这也意味着,因为它们在不同的对象上进行同步,所以多个线程将同时进入受保护的块,并且竞争条件将发生。

因为我同步的整数是全局visibile静态整数,为什么我得到不同的实例?

当值分配给一个Integer它变成一个不同对象引用 - 即使它是static。你是不是改变相同的对象,因为Integer不能突变。因此notifier = 50;将其分配给与notifier = 0;不同的对象。

如果你想使用,例如,一个恒定的对象,你可以使用一个AtomicBoolean

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

这里,AtomicInteger可以打上final,因为它是同一个对象所有的时间。

欲了解更多信息,请参见:Why is it not a good practice to synchronize on Boolean?

相关问题