我试图让Thread2等待String和Thread1在String更新时通知,我按照下面的代码显示同步String对象,但我仍然得到IllegalMonitorStateException
这里' s我的代码
public class Class1{
String string = "";
public Class1(){
Thread t1 = new Thread(){
public void run(){
synchronized(string){
string = "Something"; string.notifyAll(); //This is the line that throws an IllegalMonitorStateException
}
}
};
Thread t2 = new Thread(){
public void run(){
synchronized(string){
try{
string.wait();
}catch(Exception e){
e.printStackTrace();
}
}
}
};
t2.start();
t1.start();
}
}
除了突出显示string.notifyAll()
答案 0 :(得分:3)
您的代码包含数据争用,因为它访问string
块之外的可变synchronized
变量。具体而言,这发生在synchronized(string)
行上。取消引用string
以访问其监视器将被锁定的对象时,该线程尚未锁定该对象。因此,您无法保证它将获得锁定的对象。
mutate string
变量的事实意味着它现在指向其他一些对象。当下一个线程获得对该新对象的锁定时,它将不会受益于任何发生在之前的关系,因为它是第一个获得锁定的线程。也不保证相互排斥,因为可能存在任意多个线程,每个线程在没有争用的情况下锁定不同的String
实例。
结合上述两种现象,我们也可以看到,无法保证在synchronized(string)
行上到达的对象与在中从到达的对象相同>同步块。一旦发生这确实是一个不同的对象,您的IllegalMonitorStateException
就会发生。
总之,情况非常类似于根本不存在的synchronized
块。
如果您始终遵循使用专用final
变量来引用用于锁定的对象的最佳实践,则可以避免上述所有问题。简而言之,在您的示例中修复编译错误,这就是您必须编写的内容:
static String string = "";
static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
synchronized (lock) {
... update the string variable ...
lock.notifyAll();
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
t2.start();
t1.start();
}