As a method of synchronizaton between threads, in Java we can use the ReentrantLock
class. It has a method called tryLock()
which allows the thread not to wait if it notices that a thread has not been acquired yet. As it returns a boolean value, it can be combined with if
statements to make threads do other things if they could not acquire the lock, similar to this:
if (lock.tryLock()) {
// Do things inside the lock
lock.unlock();
} else {
// The lock was occupied, do other things
}
Things are great until there. However, let's suppose that we have two (or more) locks, and we want to get both of them before entering the critical section. In some specific situation, the first lock is available, but not the second one. In order for this scenario to work correctly, I have come up with some options to choose from. Please note that I am more worried about the unlocking of the locks, rather than their locking:
// Option 1
if (lock1.tryLock() && lock2.tryLock()) {
// Congratulations! You are inside both locks
} else {
// How to know if you got a lock, and if so, which one?
// You will need to "blindly" unlock both
try {
lock1.unlock();
lock2.unlock();
} catch (IllegalStateMonitorException e) {
// Thrown when you unlock a lock which is not yours
}
}
In my implementation, the first option basically ignored an exception, which could cause problems at some point in the execution.
// Option 2
if (lock1.tryLock()) {
if (lock2.tryLock()) {
// Congratulations! You are inside both locks
// Do things
lock2.unlock();
}
lock1.unlock();
}
This second option takes advantage of the fact that maybe the second lock was not obtained but the first one was got. I find this more efficient and intuitive.
Which option do you think is the best one? Do you have a better implementation regarding this topic?
Only ever use the second variant. The first one will cause problems, e.g. when the second lock was hold by another thread. It also doesn't unlock locks in the correct (reverse) order.