Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to lock multiple ReentrantReadWriteLocks in the same try block?

Let's say I have two critial resources, foo and bar. I protect them with some ReentrantReadWriteLocks

ReentrantReadWriteLock foo = new RRWL() ...
ReentrantReadWriteLock bar = new RRWL() ...

Most operations only use foo OR bar, but some of them happen to use both. Now when using a single lock, you can't just do this:

void foo() {
   foo.writeLock().lock();
   privateWorkOnFoo();
   foo.writeLock().unlock();
}

If an exception is thrown, your foo will become forever locked. Instead you wrap it, like

void foo() {
    try {
        foo.writeLock().lock();
        privateWorkOnFoo();
    } finally { foo.writeLock().unlock(); }
}

But what if I need to work on both? Is it safe to put them in one block?

Option 1

try {
    foo.writeLock().lock();
    bar.writeLock().lock();
    magic();
} finally { 
    bar.writeLock().unlock();
    foo.writeLock().unlock();
}

Or is it necessary to give each lock its own block:

Option 2

try {
    foo.writeLock().lock();
    try {
        bar.writeLock().lock();
        magic();
    } finally { 
      bar.writeLock().unlock();
    }
    
} finally { 
    foo.writeLock().unlock();
}

I can't have been the first person to have hard to investigate this before... I know option 2 there is "bulletproof" but it's also a significant amount more maintenance. Is option 1 acceptable?

like image 939
corsiKa Avatar asked May 05 '13 07:05

corsiKa


People also ask

What is the maximum number of threads that can possess the Writelock of a ReentrantReadWriteLock at the same time?

This lock supports a maximum of 65535 recursive write locks and 65535 read locks. Attempts to exceed these limits result in Error throws from locking methods.

How do java locks work?

Each object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that monitor are blocked until they can obtain a lock on that monitor.

What is ReentrantReadWriteLock?

ReentrantReadWriteLock class of Java is an implementation of ReadWriteLock, that also supports ReentrantLock functionality. The ReadWriteLock is a pair of associated locks, one for read-only operations and one for writing.

What are locks java?

Simply put, a lock is a more flexible and sophisticated thread synchronization mechanism than the standard synchronized block. The Lock interface has been around since Java 1.5. It's defined inside the java. util. concurrent.


2 Answers

Option 1 is fine. It's known as the two lock variant. If you look at LinkedBlockingQueue operations such as remove, it locks the putLock as well as the takeLock. Here's a sample of what the JDK does:

  public boolean remove(Object o) {
       if (o == null) return false;
       fullyLock();
       try
       {
       // ...
       }   
       finally {
         fullyUnlock();
       }
    }

   /**
     * Lock to prevent both puts and takes.
     */
    void fullyLock() {
        putLock.lock();
        takeLock.lock();
    }

    /**
     * Unlock to allow both puts and takes.
     */
    void fullyUnlock() {
        takeLock.unlock();
        putLock.unlock();
    }
like image 177
Jeremy Unruh Avatar answered Oct 21 '22 13:10

Jeremy Unruh


Option 1 is actually safer than Option 2, since if an exception is thrown in option 2, the second lock (foo) won't be unlocked: the unlocking is not in a finally block.

Also, be very careful when manipulating two locks, because there's a good chance of deadlock if one thread locks foo then bar, and another thread locks bar then foo.

like image 31
JB Nizet Avatar answered Oct 21 '22 13:10

JB Nizet