我有以下方法foo
,它接受一个观察者并将当前线程置于睡眠状态,直到观察者唤醒它。
由于某种原因,我在foo
java.lang.IllegalMonitorStateException
异常public void foo(Observer o)
{
Thread currentThread = Thread.currentThread();
o.setThread(currentThread);
// sleep until the observer wakes it
currentThread.wait(2000); // <<<<< Exception happens here
}
当Observable
调用update
时,Observer
对象将在稍后某个时间调用currentThread.notifyAll()
。
public class Observer
{
private volatile Thread currentThread;
// ... other code ....
public void setThread(Thread t)
{
currentThread = t;
}
public void update(Observable o)
{
currentThread.notify();
}
}
你知道这是怎么回事吗?
无论何时调用对象的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);
}
}
更新:
根据你的要求,我建议你应该在Observer
对象上调用wait
。所以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
}
}
那和这个问题不一样。我不能把synchronized放在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
这样的变化。
我不希望你使用wait
或notify
,因为它是低级别的,如果没有很好地实现,很快就会变脏。可通过二进制信号量求解。
Semaphore sem = new Semaphore(0);
public void foo(Semaphore f){
f.acquire();
}
其他线程,可以稍后调用f.release
,这将解除阻塞其他线程
要使用java.lang.Object.wait(),您必须拥有监视器,它通常由同步块完成:
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();
}
}
您可以使用同步的。当您调用currentThread.wait()时,线程将休眠并释放监视器(currentThread)。这个线程将等待另一个线程在同一监视器上使用notify()唤醒。