Home > database >  Understanding ReadWrite locks in Java
Understanding ReadWrite locks in Java

Time:12-31

While a write lock is being held, Read lock can be acquired. But not vice versa. What is the rationale for this design choice.

  public static void main(String[] args)
    {
        System.out.println("read to write test");
        ReadWriteLock lock = new ReentrantReadWriteLock();
        
        lock.writeLock().lock();
        lock.readLock().lock();
        
        System.out.println("Read locks can be acquired after  Write locks are acquired as well.");
    }

Output of above code:

read to write test
Read locks can be acquired after  Write locks are acquired as well.

Vice versa doesn't work.

public static void main(String[] args) throws InterruptedException {


        ReadWriteLock lock = new ReentrantReadWriteLock();


        lock.readLock().lock();
        
        System.out.println("Read lock is  acquired");
        System.out.print("Trying to get write lock. ");

        boolean  writeLockAcquired =  lock.writeLock().tryLock(120, TimeUnit.SECONDS);
        if (! writeLockAcquired){
            System.out.println("Even after 120 seconds, we  couldn't get write lock");
        }
        else{
            System.out.println("We could get write lock.");
        }
        
    }

Here is the output:

Read lock is  acquired
Trying to get write lock. Even after 120 seconds, we  couldn't get write lock

Can some one point to snippets in Java open source projects to look at practical usage of Read Write locks. I understand that there are a lot of Java open source projects like ElasticSearch / Hadoop / Spark etc.

CodePudding user response:

While a write lock is being held, Read lock can be acquired.

Locking is to protect against access by concurrent threads.

A read-write lock allows multiple concurrent readers OR a single writer thread.

If a thread owns the write lock, it already has exclusive access, so there's no harm in granting it read access. It will not conflict with itself.

If a thread owns the read lock, there is no guarantee it has exclusive access, so granting the write lock is disallowed. There is no benefit in special-casing the 'single thread wanting both locks' situation.

In other systems, the lock modes are referred to as 'exclusive' (= write) and 'shared' (= read) modes. Considering those terms might help clarify the situation.

There is further rationale in the documentation for the reentrant read-write lock:

Additionally, a writer can acquire the read lock, but not vice-versa. Among other applications, reentrancy can be useful when write locks are held during calls or callbacks to methods that perform reads under read locks. If a reader tries to acquire the write lock it will never succeed.

CodePudding user response:

Allowing a read lock to be upgraded to a write lock would be a source of deadlocks:

  • Thread A takes a read lock (now no one can take a write lock)
  • Thread B takes a read lock
  • Thread A decides to upgrade to a write lock -- blocks
  • Thread B decides to upgrade to a write lock -- deadlock

The correct way to do this (when you are doing an operation which may need a write lock, but usually doesn't) is to retry it:

  • Thread A takes a read lock
  • Thread B takes a read lock
  • Thread A decides it needs a write lock
  • Thread A drops the read lock
  • Thread A tries to take the write lock -- blocks because A holds the read lock
  • Thread B decides it needs a write lock
  • Thread B drops the read lock
  • Thread A gets the write lock
  • Thread B tries to take the write lock and blocks
  • Thread A finishes its work and releases the lock
  • Thread B takes the write lock
  • Related