CurrentThreadNotOwner

April 12, 2005
Since I burned way too many “duh?” hours getting this straight in me noggin’, I'll post my learning for my future self who's bound to forget this.

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