我正在进入Java多线程。我对C / C ++ pthreads非常熟悉,但是我遇到了Java notify()
和wait()
函数的问题。
我理解只有当一个不“拥有”(又名没有同步)的线程调用notify / wait时才会抛出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),似乎在Integer上同步并不是一个好主意,因为很难确保你在同一个实例上进行同步。由于我正在同步的整数是一个全局可见静态整数,为什么我会得到不同的实例?
答案 0 :(得分:5)
由于notifier = 50;
您在另一个对象上调用notifier.notify();
。
答案 1 :(得分:0)
最初,当您在非主线程中调用notifier
上的synchronized时,它正在引用内容为0
的堆上的对象,因此该线程拥有该对象。现在,在使用wait
将非主线程置于notifier.wait
之后,将控制权交给主线程。在获取包含值0的Integer对象的锁之后,您使notifier
引用包含值50
的堆内存上的另一个对象,因为notifier = 50;
实际上等同于notifier = new Integer(50)
表示创建Integer
的新对象,并将其引用传递给notifier
。现在,当线程看到notifier.notify
时,它看起来主线程现在不再拥有它之前获得的原始对象。所以IllegalMonitorStateException
正在投掷。
答案 2 :(得分:0)
只是为了添加更多信息,您永远不应该在非最终对象上进行同步。
您需要在常量对象上进行同步。如果您同步了您正在分配的任何对象(即更改对象),则该对象不是常量,一旦它分配了对象并尝试通知它,您将获得IllegalMonitorStateException
。它还意味着因为它们在不同的对象上同步,所以多个线程将同时进入受保护的块并且将发生竞争条件。
由于我正在同步的整数是一个全局可见静态整数,为什么我会得到不同的实例?
为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?