我有跟随方法foo
,它接受一个Observer并将当前线程置于休眠状态,直到Observer唤醒它。
出于某种原因,我在java.lang.IllegalMonitorStateException
foo
例外
public void foo(Observer o)
{
Thread currentThread = Thread.currentThread();
o.setThread(currentThread);
// sleep until the observer wakes it
currentThread.wait(2000); // <<<<< Exception happens here
}
Observer
对象稍后会在其currentThread.notifyAll()
调用Observable
时调用update
。
public class Observer
{
private volatile Thread currentThread;
// ... other code ....
public void setThread(Thread t)
{
currentThread = t;
}
public void update(Observable o)
{
currentThread.notify();
}
}
知道这里有什么问题吗?
答案 0 :(得分:3)
每当您调用对象的wait(long)
或notify()
方法时,该线程必须拥有该对象的监视器。因此,您应该声明在对象上调用wait()
的代码块为synchronized
。所以你的方法
public void foo(Observer o)
应按以下方式定义:
public void foo(Observer o)
{
Thread currentThread = Thread.currentThread();
o.setThread(currentThread);
// sleep until the observer wakes it
synchronized(currentThread)
{
currentThread.wait(2000);
}
}
更新:
根据您的要求,我建议您在wait
对象上调用Observer
。所以foo
的代码应该是这样的:
public void foo(Observer o)
{
synchronized(o)
{
o.wait();//Don't pass time as parameter. Let only the Observer object to wake it up.
}
}
您的Observer
课程应该以这种方式定义:
public class Observer
{
// ... other code ....
/*public void setThread(Thread t)
{
currentThread = t;
}*/
public synchronized void update(Observable o)
{
notify();//Will wake up the Thread waiting on the current Object of Observer
}
}
答案 1 :(得分:2)
这与这个问题不一样。我不能把同步放在foo中,因为这会导致线程永远睡眠。
我认为您不了解wait()
和notify()
的工作原理。你不等待并通知线程,你在同一个对象上做。代码执行时:
currentThread.wait(2000);
它实际上导致当前线程在它自己的Thread
对象上等待。 notify()
该线程的方式如下:
Thread thread = new Thread(myRunnable);
...
thread.notify();
这是非常奇怪的模式,很可能不你想做什么。运行foo()
方法的哪个线程无关紧要。如果您使用的是线程池,您甚至不知道哪个线程正在运行它。
如果您希望Observer
线程通知在foo()
中等待的线程,则它们都需要使用相同的锁对象。类似的东西:
class MyClass {
...
public synchronized void foo() {
// this is waiting on the current instance of MyClass
wait(2000);
}
}
public class Observer {
...
// to wake up the other thread, we lock the same myClass instance
synchronized (myClass) {
// and notify that object
myClass.notify();
}
}
或者您可以创建一个他们都应该共享的锁定对象。
final Object lockObject = new Object();
MyClass c1 = new MyClass(lockObject);
Observer obs = new Observer(lockObject();
...
class MyClass {
private final Object lockObject;
public MyClass(Object lockObject) {
this.lockObject = lockObject;
}
...
public void foo() {
// this is waiting on the current instance of MyClass
synchronized (lockObject) {
lockObject.wait(2000);
}
}
}
...
public class Observer {
private final Object lockObject;
public Observer(Object lockObject) {
this.lockObject = lockObject;
}
public void update(Observable o) {
synchronized (lockObject) {
lockObject.notify();
}
}
}
仅供参考:锁定对象几乎应始终为final
,因此无法更改其引用。您永远不想锁定像Integer
或Boolean
更改的内容。
答案 2 :(得分:1)
我不希望你使用wait
或notify
,因为它是低级别的,如果没有很好地实现,会很快变脏。它可以通过二进制信号量来解决。
Semaphore sem = new Semaphore(0);
public void foo(Semaphore f){
f.acquire();
}
其他线程,稍后可以调用f.release
来取消阻止其他线程
答案 3 :(得分:0)
要使用java.lang.Object.wait()您必须拥有显示器,通常由synchronized block完成:
public void foo( Observer o ) throws InterruptedException
{
Thread currentThread = Thread.currentThread();
o.setThread( currentThread );
synchronized( currentThread ) {
currentThread.wait( 2000 );
}
}
在notify()
周围添加相同的机制public void update( Observable o ) throws InterruptedException {
synchronized( currentThread ) {
currentThread.notify();
}
}
答案 4 :(得分:0)
您可以使用同步。当您调用currentThread.wait()时,线程将休眠并释放监视器(currentThread)。该线程将等待另一个线程在同一监视器上使用notify()唤醒。