Essence Java Framework
This web site is being migrated to the Essence Wiki
Google
 
Web www.jtoolkit.org weblog.jtoolkit.org
Navigation
Home
SourceForge Home
Articles on Java
Getting Started
Essence Documentation
Download

Contact
Get rewarded for helping out
Email A Question
Weblog

Support This Project

SourceForge.net Logo

Articles Home

ReentrantReadWriteLock and Lock upgrading.

The Java 5 concurrency library has a lock which supports exclusive and non-exclusive barriers. Using this lock you can have multiple threads to obtain read access or one thread to obtain write access.

This can significantly improve performances where there is read contention on an object.

Typical read block

try {
    lock.readLock().lock();
    // do something
} finally {
    lock.readLock().unlock();
}
If you attempt to obtain a write lock while holding the read lock, it will silently block forever.

NOTE: The JVM does not detect this deadlock.

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
try {
    // try to obtain lock.
    readWriteLock.readLock().lock();
    // try to obtain writeLock. This fails as upgrading results in a deadlock.
    assertFalse(readWriteLock.writeLock().tryLock(100, TimeUnit.MILLISECONDS));
} finally {
    readWriteLock.readLock().unlock();
}
You can code a wrapper to detect deadlock conditions. The RWLock can be used to either detect this deadlock or even allow upgrading.

Detect a deadlock condition

ReadWriteLock readWriteLock = new RWLock("test_upgradeLock2", false);
try {
    // try to obtain lock.
    readWriteLock.readLock().lock();
    // try to obtain writeLock. This fails as upgrading results in a deadlock.
    fail("Expected IllegalMonitorStateException, got=" + readWriteLock.writeLock().tryLock(100, TimeUnit.MILLISECONDS));
} catch (IllegalMonitorStateException expected) {
    assertEquals("test_upgradeLock2: Cannot be upgraded from readLock to writeLock", expected.getMessage());
} finally {
    readWriteLock.readLock().unlock();
}
The RWLock can be configured to allow upgrading. However for performance reason you are better off changing your code so that it doesn't attempt to upgrade the lock.

Allows upgrades

ReadWriteLock readWriteLock = new RWLock("test_upgradeLock3", true);
boolean okay = false;
try {
    // try to obtain lock.
    readWriteLock.readLock().lock();
    // try to obtain writeLock. This succeeds as .
    assertTrue(readWriteLock.writeLock().tryLock(100, TimeUnit.MILLISECONDS));
    okay = true;
} finally {
    // if the test failed do not obscure the cause with another exception.
    try {
        readWriteLock.writeLock().unlock();
    } catch (RuntimeException ignored) {
        if (okay)
            throw ignored;
    }
    try {
        readWriteLock.readLock().unlock();
    } catch (RuntimeException ignored) {
        if (okay)
            throw ignored;
    }
}

Detecting that a thread holds a lock.

Holding a lock while performing an unrelated long running task can seriously impact your performance. It is not a deadlock condition, it just slows down your application.

Detecting that a lock is being held

if (RWLock.isDebug())
    RWLock.checkUnlocked("read from " + name + ' ' + objectName);
Accessing disk or waiting for a network request can be undesirable However, using RWLock has its own overhead so its use can be selectable.
// Uses System property "rwlock.debug" to enable.
ReadWriteLock lock = RWLock.createLock(name);

Downloads

Copyright 2006 Peter Lawrey Essence Email