I have the follow method foo which takes an Observer and puts the current thread to sleep until the Observer wakes it up.
For some reason, I keep getting java.lang.IllegalMonitorStateException exception in 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
}
The Observer object would call currentThread.notifyAll() sometime later when its Observable calls update on it.
public class Observer
{
private volatile Thread currentThread;
// ... other code ....
public void setThread(Thread t)
{
currentThread = t;
}
public void update(Observable o)
{
currentThread.notify();
}
}
Any idea what is wrong here?
Whenever you call wait(long) or notify() method of object , that thread must own the monitor of that object. So you should declare your block of code calling wait() on the object to be synchronized . So your method
public void foo(Observer o)
should be defined in following way:
public void foo(Observer o)
{
Thread currentThread = Thread.currentThread();
o.setThread(currentThread);
// sleep until the observer wakes it
synchronized(currentThread)
{
currentThread.wait(2000);
}
}
UPDATE:
Going by your requirement I suggest you that you should call wait on Observer object . So your code for foo should be something like this:
public void foo(Observer o)
{
synchronized(o)
{
o.wait();//Don't pass time as parameter. Let only the Observer object to wake it up.
}
}
And your Observer class should be defined in this way:
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
}
}
That's is NOT the same as this question. I cannot put synchronized in foo because that would cause the thread to sleep forever.
I don't think you are understanding how wait() and notify() work. You do not wait and notify on the threads, you do it on the same object. When your code does:
currentThread.wait(2000);
it is actually causing the current thread to wait on it's own Thread object. The way to notify() that thread would then be something like:
Thread thread = new Thread(myRunnable);
...
thread.notify();
This is a very strange pattern and is most likely not what you want to do. It shouldn't matter which thread is running the foo() method. If you were using a thread-pool you wouldn't even know which thread was running it.
If you want your Observer thread to notify the thread waiting in foo() then they both need to be working with the same lock object. Something like:
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();
}
}
Or you could create a lock object that they both should share.
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();
}
}
}
FYI: Lock objects should almost always be final so they can't change their reference. You never want to lock on something that changes like an Integer or a Boolean.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With