According to Java doc, when obj1.wait()
happens, "The thread releases ownership of this monitor and waits until another thread notifies..."
So, the lock of obj1 is freed, while the current thread is waiting. But what about all other locks? It is possible, that the piece of the code is locking two objects:
synchronized(obj2){
f1();
synchronized(obj1){
f2();
obj1.wait();
}
}
Obj2 won't be freed, but the thread does not run, another thread will wait for freeing of obj2 in vain... I don't understand the reason of that continuing locking of obj2. But OK, it is as it is.
But how can I organize this waiting better, how can I unlock for the time of waiting all or at least several current locks?
You could use Locks and Conditions which are more flexible than sychronized
statements.
For your example you could replace obj2
with a ReentrantLock
:
Lock lock2 = new ReentrantLock();
try {
// Blocks until the lock is acquired, just like a `synchronized` statement
lock2.lock();
f1();
synchronized (obj1) {
f2();
lock2.unlock();
obj1.wait();
lock2.lock();
}
}
// Use `finally` to make sure the lock is always released, even if an exception is thrown
finally {
// Exception might have been thrown before current thread could acquire lock again, cannot
// unlock then
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
}
However, this would allow another thread to acquire lock2
before the current thread starting waiting for obj1
. If this is not desired you could replace obj1
with a Lock
instead and wait for obj2
.