我得到了java.lang.IllegalMonitorStateException
。我提到this问题,它解决了我的问题。第一个答案是
To be able to call notify() you need to synchronize on the same object.
synchronized (someObject) {
someObject.wait();
}
/* different thread / object */
synchronized (someObject) {
someObject.notify();
}
我的问题是为什么我们需要在同一个对象广告上同步它?
据我所知,当我们说
时synchronized (someObject) {
someObject.wait();
}
我们在对象someObject上获得一个锁,然后我们在它上面调用wait()。 现在,另一个线程怎么能锁定同一个对象来调用notify()?我缺少什么?
答案 0 :(得分:8)
为什么notify
也需要锁定?
想象一下这种情况:
synchronized(x){
while(x.count < 4) {
x.wait();
//...
}
}
现在想象一下notify
在其他地方没有任何锁定:
//...
println(x.count); // print 3
x.count++;
if(count == 4)
x.notify()
//...
乍一看,整个声音始终按预期工作 但是,想象一下这种竞争条件:
//Thread1 enters here
synchronized(x){
while(x.count < 4) {
//condition is judged true and thread1 is about to wait
//..but..ohh!! Thread2 is prioritized just now !
//Thread2, acting on notify block side, notices that with its current count incrementation,
//count increases to 4 and therefore a notify is sent....
//but...but x is expected to wait now !!! for nothing maybe indefinitely !
x.wait();
//maybe block here indefinitely waiting for a notify that already occurred!
}
}
如果我们有办法告诉notify
方:
线程1:“哼哼.. notify
,你很可爱,但我刚刚开始评估我的情况(x.count < 4
)为真,所以请...不要愚蠢刚刚发送您的预期通知(在我将状态等待之前),否则,等待已经通过的事情我会很荒谬“
线程2:“好的好吧......为了保持一致,我会锁定我的逻辑,以便在等待调用后发送我的通知释放我们的共享锁,从而你将收到此通知,允许退出等待状态;)“
因此,总是在notify
侧,在等待的同一对象上放置一个锁,以避免这种情况并让关系始终保持一致。
<强> =&GT;导致notify
的逻辑和导致wait
的逻辑不应重叠。
答案 1 :(得分:5)
当前主题必须拥有此对象的监视器。线程发布 此监视器的所有权,并等待另一个线程通知 在这个对象的监视器上等待通过a唤醒的线程 调用notify方法或notifyAll方法。线程然后 等到它可以重新获得监视器的所有权并恢复 执行。
要使用wait / notify,线程必须具有锁定,否则 IllegalMonitorStateException被抛出
抛出: IllegalMonitorStateException - 如果当前线程不是 对象监视器的所有者。
所以,
wait()
使当前线程释放锁定
notify()
发出其他等待线程的信号,然后尝试获取锁。
要么这样做,当前线程必须具有锁定。这很有道理!
为什么线程调用wait()保持锁定现在非常明显。
但是为什么线程调用notify()会持有锁?好吧,首先,要证明它的authenticity
。否则,任何线程都可能继续触发false notifications
,并且waiting
线程将继续被中断。 幸好情况并非如此。
答案 2 :(得分:1)
wait / notify通常用于等待某个其他线程完成任务,或者等到满足某个条件。
假设我们有一个名为 objectA 的对象和两个名为 thread1和thread2 的线程。
thread1 具有一些线程安全任务,因此它使用 synchronized 块获取objectA的监视器。
synchronized (objectA) {
//here thread1 owns objectA's monitor
}
在java调用中,wait()意味着释放监视器,以便其他线程可以获取此监视器并完成其任务,当前线程进入某个状态,称为等待状态,用于objectA的监视器。
synchronized(objectA){
//here thread1 owns objectA's monitor.
objectA.wait();
//here thred1 releases monitor of objectA's monitor and goes into waiting state and waits to get objectA's monitor once again to complete its task.
}
现在,thread2可以拥有objectA的监视器并执行其任务。
synchronized(objectA){
//here thread2 owns objectA's monitor.
//some task;
}
任务完成后,它会通知处于等待状态的其他线程,它会在其拥有的对象上释放监视器。 请注意,要调用 notify(),线程也应该是对象监视器的所有者。
synchronized(objectA){
//here thread2 owns objectA's monitor.
//some task;
objectA.notify();
//it signals some other thread that it can wake up from wait,so that other waiting threads can owns objectA's monitor
}
在objectA上调用wait()并在其他对象上调用notify()(比如说objectB)对 thread1 没什么用。来自 thread1 等待获取监视器on objectA 而不是其他对象(比如说objectB)。
更新的
Why obtain monitor to call notify()
要调用 notify()我们需要获取监视器,因为可以保证两个线程试图在一个对象上调用notify()不会踩到彼此的脚趾(以避免竞争条件)。登记/>
why we need to get lock before notify
答案 3 :(得分:0)
查看Hotspot JVM源代码,我发现:notify()
方法修改了对象监视器的等待集。 (对象的等待集是在其上调用wait()
的线程集。)如果对等待集的访问未同步,则可能发生坏事:例如,可以从集合中删除线程永远被唤醒在调用notify()
之前要求调用线程拥有监视器解决了这个问题,尽管其他解决方案也可能存在。
还有其他一些参数,例如在没有持有监视器的情况下调用通知通常意味着程序员错误,但我认为这不足以激发这样的限制。