It is sometimes required for a process to concurrently write and read the same "data".
The ReadWriteLock
interface, and its ReentrantReadWriteLock
implementation allows for an access pattern that can be described as follow :
An implementation could look like :
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Sample {
// Our lock. The constructor allows a "fairness" setting, which guarantees the chronology of lock attributions.
protected static final ReadWriteLock RW_LOCK = new ReentrantReadWriteLock();
// This is a typical data that needs to be protected for concurrent access
protected static int data = 0;
/** This will write to the data, in an exclusive access */
public static void writeToData() {
RW_LOCK.writeLock().lock();
try {
data++;
} finally {
RW_LOCK.writeLock().unlock();
}
}
public static int readData() {
RW_LOCK.readLock().lock();
try {
return data;
} finally {
RW_LOCK.readLock().unlock();
}
}
}
NOTE 1 : This precise use case has a cleaner solution using AtomicInteger
, but what is described here is an access pattern, that works regardless of the fact that data here is an integer that as an Atomic variant.
NOTE 2 : The lock on the reading part is really needed, although it might not look so to the casual reader. Indeed, if you do not lock on the reader side, any number of things can go wrong, amongst which :
data
were a 64bits long typeIn case higher performance is required, an under certain types of usage, there is a faster lock type available, called the StampedLock
, that amongst other things implements an optimistic lock mode. This lock works very differently from the ReadWriteLock
, and this sample is not transposable.