javamultithreadingconcurrencyreentrantlockjava-15

Reentrant lock implementation detail


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:

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?


Solution

  • 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.