为什么会抛出IllegalMonitorStateException?
我正在进入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),它似乎不是在整型同步,因为这是很难确保你是在同一个实例进行同步是个好主意。因为我正在同步的整数是全局可见的静态整数,为什么我得到不同的实例?
由于notifier = 50;
要调用不同的对象上notifier.notify();
。
最初,当您在非主线程中调用同步notifier
时,它引用堆中的对象,其内容为0
,因此线程拥有该对象。现在,在使用notifier.wait
将非主线程放在wait
后,控制权交给了主线程。在获取包含值0的Integer对象的锁之后,您使notifier
引用包含值50
的堆内存上的另一个对象,因为notifier = 50;
实际上等于notifier = new Integer(50)
,这意味着将创建一个新对象Integer
并将其参考传递给notifier
。现在,当线程看到notifier.notify
时,它看起来主线程现在不再拥有它之前获得的原始对象。所以IllegalMonitorStateException
正在抛出。
只需添加更多的信息,你不应该在非最终目标上同步。
你需要一个恒定对象上同步。如果您正在分配(即改变物体)的任何对象上同步,则对象不是恒定的,一旦分配对象,并设法通知它,你会得到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?
可能重复:HTTP://stackoverflow.com/questions/659915/synchronizing-on-an-integer-value – Cratylus 2013-03-23 19:26:59
又一个暗示,因为它已经有了答案:尝试将通知设置为最终。由于您为通知程序指定了不同的值(对象),因此它不会编译。 – 2013-03-23 20:07:11