Search code examples
javamultithreadingreentrantlock

ReentrantReadWriteLock fails to get lock even when its state is Unlocked


I am trying to get lock on a thread using following piece of code:

Lock lock = readLock ? getLock(key).readLock() : getLock(key).writeLock();
try {
    boolean locked = lock.tryLock(DEFAULT_TRY_TIME, DEFAULT_TRY_TIME_UNIT); //line 3
    // If false, lock is not acquired
    if (!locked) {
        throw new TryLockTimeoutException(
                key + ": Failed to acquire " + lock + " within " + DEFAULT_TRY_TIME_STRING);
    }
}

Line 3 returns false after 30 minutes hence TryLockTimeoutException is thrown with error as:

com.concurrent.TryLockTimeoutException: keyIp : Failed to acquire java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock@74be2cee[Unlocked] within 30MINUTES
    at com.concurrent.NeAccessLockMap.acquireReadOrWriteLock(NeAccessLockMap.java:72)

Notice that lock state is shown as Unlocked in error.

I am not able to understand why would this happen? Why thread is not able to get lock even when the lock is free.


Solution

  • In your example you try to acquire a write lock, but the read lock is already locked, which prevents you from acquiring the write lock.

    Because you can either have one or more read locks acquired, or a single write lock acquired, the write lock is marked as Unlocked when there are read locks acquired.

    Try the following code:

    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    new Thread() {
        @Override
        public void run() {
            readWriteLock.readLock().lock();
            try {
                // block the read lock
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }.start();
    if (!readWriteLock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
        System.out.println(readWriteLock);
        System.out.println(readWriteLock.readLock());
        System.out.println(readWriteLock.writeLock());
    }
    

    would have output like:

    java.util.concurrent.locks.ReentrantReadWriteLock@31221be2[Write locks = 0, Read locks = 1]
    java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock@377dca04[Read locks = 1]
    java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock@728938a9[Unlocked]