I am trying to understand a particular detail in ReentrantLock::lock
method. I am looking at it and seeing it as:
final void lock() {
if (!initialTryLock()) {
acquire(1);
}
}
So first it tries this method : initialTryLock
(I will look in NonfairSync
), which does this:
compareAndSwap(0, 1)
, meaning if no one holds the lock (0
) and I can grab it (1
), I hold the lock now.false
, meaning I could not acquire the lock.Let's assume the above failed. It then goes on and calls acquire
in AbstractQueuedSynchronizer
:
public final void acquire(int arg) {
if (!tryAcquire(arg))
acquire(null, arg, false, false, false, 0L);
}
It calls tryAcquire
first in NonfairSync
:
protected final boolean tryAcquire(int acquires) {
if (getState() == 0 && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
You can see that it tries to acquire the lock again, though the initialTryLock
already failed. In theory, this tryAcquire
could have simply returned false
, right?
I see this as a potential retry, because between the calls of initialTryLock
and tryAcquire
, the lock might have been released. The benefit of this might be that because the next operation (after tryAcquire
) fails, is the expensive enqueue of this thread. So I guess this makes sense (to retry) because of that?
Just to add to the answer above.
tryAcquire
could have simply returned false, right?
No.
This implementation:
boolean tryAcquire(int acquires) {
return false;
}
would break the work of AbstractQueuedSynchronizer
.
The reason is that tryAcquire()
is the only way to take the lock in AbstractQueuedSynchronizer
.
Even acquire()
in the end uses tryAcquire()
.
So if tryAcquire()
always returned false
then acquire()
would never acquire the lock.
And acquire()
is used when several threads contend for the lock.