问题描述
我试图让Thread2等待String和Thread1通知String更新,我确实同步了String对象,如下面的代码所示,但是我仍然得到IllegalMonitorStateException
这是我的代码
I'm trying to have a Thread2 wait for a String and Thread1 to notify on String update, I do synchronize The String object as code below shows, But I still get IllegalMonitorStateException
Here's my code
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()
推荐答案
-
您的代码包含一个数据竞争,因为它访问了
synchronized
块之外的可变string
变量.具体来说,这发生在行synchronized(string)
上.在取消引用string
以到达其监视器将被锁定的对象时,线程尚未对该对象持有锁定.因此,您无法保证它将锁定哪个对象.
Your code contains a data race because it accesses the mutable
string
variable outside of asynchronized
block. Specifically, this happens on the linesynchronized(string)
. While dereferencingstring
to reach the object whose monitor will be locked, the thread does not already hold a lock on that object. Therefore you have no guarantee which object it will acquire a lock on.
您对string
变量进行了变异的事实意味着,该变量现在指向其他对象.当下一个线程获得对该新对象的锁定时,它将不会从任何 happens-before 关系中受益,因为它是第一个获得该锁定的线程.也不能保证互斥,因为可能有任意多个线程,每个线程锁定一个不同的String
实例而没有争用.
The fact that you mutate the string
variable means that it now points to some other object. When the next thread acquires a lock on that new object, it will not benefit from any happens-before relationship because it is the first thread to ever acquire a lock on it. Mutual exclusion will not be guaranteed, either, because there may be arbitrarily many threads, each locking a different String
instance without contention.
结合上述两种现象,我们还可以看到,不能保证在行synchronized(string)
上到达的对象将与在内到达的对象相同.同步块.一旦碰巧这确实是一个不同的对象,您的IllegalMonitorStateException
就会随之发生.
Combining the two phenomena described above we can also see that there is no guarantee that the object reached on the line synchronized(string)
will be the same one as the one reached from within the synchronized block. Once it happens that this is indeed a different object, your IllegalMonitorStateException
ensues.
总而言之,情况与根本不存在的synchronized
块非常相似.
In summary, the situation is very similar to the synchronized
block not existing at all.
如果您坚持使用专用的final
变量来引用用于锁定的对象的最佳实践,则可以避免上述所有问题.简而言之,并修复示例中的编译错误,这是您必须编写的:
All of the above problems can be avoided if you keep to the best practice of using dedicated final
variables to refer to objects used for locking. In a nutshell, and fixing the compilation errors in your example, this is what you would have to write:
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();
}
这篇关于Java同步的字符串IllegalMonitorStateException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!