wait(), wait(int), notify(), notifyAll() methods must be called from within a synchronized method or body of a synchronized block. Right? No problem.Point 1: These methods are not magical global methods for all of the VM.
For some reason I was secretly assuming this piece of fiction to be true all the while trying to figure out why a notify() call on one thread was not affecting a wait(int) call on another thread. I've no idea why I assumed this. They're clearly documented as instance methods of Object. I'm an idiot, I suppose.
So ... the following notify()/wait() calls in this snippet have nothing to do with each other:
Thread t1 = new Thread() {
public void run() {
synchronized(this) {
wait(1000);
// necessary try/catch stuff needed to compile not included
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized(this) {
notify();
}
}
};
t1.start();
t2.start();
Both threads will run, thread 1 will sleep a whole second, never to be affected by the notify() call of thread 2, because thread 1 is waiting for a notify call on the t1 instance. Thread 2 calls notify on the t2 instance. Different instances, no link.
Point 2: the instance that receives the notify()/wait() call must be the same instance that's being synchronized on.
So, back to the last example, it can't be fixed like this:
final Object mutex = new Object();
Thread t1 = new Thread() {
public void run() {
synchronized(mutex) {
wait(1000);
// necessary try/catch stuff needed to compile not included
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized(mutex) {
notify();
}
}
};
t1.start();
t2.start();
Now both the wait() and notify() calls will throw IllegalMonitorStateException: “current thread not owner”. Remember, wait() and notify() are being called on
this:final Object mutex = new Object();
Thread t1 = new Thread() {
public void run() {
synchronized(mutex) {
this.wait(1000); // THIS != MUTEX
// necessary try/catch stuff needed to compile not included
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized(mutex) {
this.notify(); // THIS != MUTEX
}
}
};
t1.start();
t2.start();
We synchronized on mutex, but tried to call wait()/notify() on this. That breaks the original rule.
This is how to fix it up:
final Object mutex = new Object();
Thread t1 = new Thread() {
public void run() {
synchronized(mutex) {
mutex.wait(1000); // THIS != MUTEX
// necessary try/catch stuff needed to compile not included
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized(mutex) {
mutex.notify();
}
}
};
t1.start();
t2.start();
Now t1 will terminate as soon as t2 calls notify.
tags: ComputersAndTechnology JavaBits