import java.util.*;
import java.io.*;
import java.util.regex.*;
class ZiggyTest2 extends Thread{
String sa;
public ZiggyTest2(String sa){
this.sa = sa;
}
public void run(){
synchronized(sa){
while(!sa.equals("Done")){
try{
sa.wait();
}catch(InterruptedException is){System.out.println("IE Exception");}
}
}
System.out.println(sa);
}
}
class Test{
private static String sa = new String("Not Done");
public static void main(String[] args){
Thread t1 = new ZiggyTest2(sa);
t1.start();
synchronized(sa){
sa = new String("Done");
sa.notify();
}
}
}
当我运行上述程序时,我得到以下异常:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at Test.main(ZiggyTest2.java:35)
几个问题:
为什么IllegalMonitorStateException?因为Test.sa被分配给一个新的String对象,所以我期望ZiggyTest2线程无限期地等待,因为sa.notify()将在与ZiggyTest2中使用的锁不同的锁上被调用。
在上面的示例中,wait()&在“sa”对象上调用notify()。如果自己调用notify()并使用对象(即sa.wait()和sa.notify()调用notify()/ wait())有什么区别?
在Test类中,synchronized块是否具有sa对象的锁并且sa对象是静态的,但是在ZiggyTest2类中,synchronized块使用相同的sa对象引用但使用非静态参考?鉴于一个是静态的而另一个不是静态的,它们是否仍然使用相同的锁?
答案 0 :(得分:2)
执行时
sa = new String("Done");
您不会通过sa
更改字符串引用的内容。您将新的String实例(新对象)分配给sa
。字符串是不可变的。改变他们的价值是不可能的。
这意味着您在sa上同步(第一个对象:“Not Done”),然后将新对象分配给sa(第二个对象:“Done”),并在第二个对象上调用notify。由于您没有同步第二个对象,但是在第一个对象上,您会收到IllegalMonitorException。仅当您拥有对象的内部锁定时,才允许在对象上调用通知。这就是锁定永远是最终的原因。
调用notify()等同于调用this.notify()。因此this.notify()
和sa.notify()
只是在两个不同的对象上调用notify()
。第一个将通知等待this
的线程,第二个将通知等待sa
的线程。
变量是静态的事实并不重要。锁与对象相关联,而不是与其引用相关联。