Explicit locks in Java 5 (ctd)
Read-write locks
In cases of shared objects where reads far outnumber writes and where accesses
are relatively non-trivial, it may be worth using a read/write lock.
This is a lock where, provided no thread owns the write lock, multiple threads are
permitted to hold read locks simultaneously.
In the Java 5 concurrency library, a read/write lock interface has been defined
and implemented by the ReentrantReadWriteLock class. The interface exposes
two underlying locks for reading and writing:
public interface ReadWriteLock {
public Lock readLock();
public Lock writeLock();
}
These individual locks then work as described on the previous page where
we described the Lock
interface. For example, to protect access to an array with a read/write lock
we could write something like the following:
public void ConcurrentIntegerArray {
private final ReadWriteLock rwl =
new ReentrantReadWriteLock();
private final int[] arr;
public ConcurrentIntegerArray(int size) {
arr = new int[size];
}
public int get(int index) {
Lock l = rwl.readLock();
l.lock();
try {
return arr[index];
} finally {
l.unlock();
}
}
public void set(int index, int val) {
Lock l = rwl.writeLock();
l.lock();
try {
arr[index] = val;
} finally {
l.unlock();
}
}
}
Notice how we wrap a read from the array in a lock/unlock operation on the
read lock, and a write to the array with a lock/unlock on the write lock.
Multiple threads will be allowed to read from the array simultaneously, but only
one thread can write at any one time.
Fairness
While a thread holds the write lock, other threads are prohibited from acquiring
a read lock. Conversely, a thread wanting to write must wait for all readers to
relinquish their locks before being able to acquire the write lock. By default,
this can mean that writing threads are heavily penalised in favour of readers:
if there are several readers, it can take the writer a comparatively long time to
acquire the lock. Of course, read/write locks are generally designed for cases
where writes are rare compared to reads. In some cases, it may be appropriate to
instantiate ReentrantReadWriteLock as "fair". In this mode, readers will
be prohibited from acquiring the lock while there are threads waiting to acquire
the write lock, and locks will generally be acquired in "first-come-first-served"
order. As with fair locks generally, there is generally a high
throughput penalty for requiring a read/write lock to be fair.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.