@Immutable
public final class ReadWriteThreadLock
extends java.lang.Object
ReentrantReadWriteLock used to synchronize threads within the same JVM,
even in the presence of multiple custom class loaders.
When attempting to synchronize threads within the same JVM (e.g., making sure that only one instance of a class executes some action at a time), we may choose to create a lock associated with the class and require instances of the class to acquire the lock before executing.
However, if that class is loaded multiple times by different class loaders, the JVM considers them as different classes, and there would be multiple locks associated with those classes. The desired effect of synchronizing all threads within the JVM is not achieved; instead, each lock can only take effect for instances of the same class loaded by the same class loader.
We create this class to address that limitation. A ReadWriteThreadLock can be used to
synchronize *all* threads in a JVM, even when a class using ReadWriteThreadLock or the
ReadWriteThreadLock class itself is loaded multiple times by different class loaders.
Threads will be synchronized on the same lock object (two lock objects are the same if one
equals() the other). The client using ReadWriteThreadLock will provide a lock object when
constructing a ReadWriteThreadLock instance. Then, different threads using the same or
different ReadWriteThreadLock instances on the same lock object can be synchronized.
Note that ReadWriteThreadLock requires the type (class) of the lock object to be
loaded by a single class loader, as objects of the same type loaded by different class loaders
cannot be compared (one never equals() the other).
The basic usage of this class is similar to ReentrantReadWriteLock and Lock. Below is a typical example.
ReadWriteThreadLock readWriteThreadLock = new ReadWriteThreadLock(lockObject);
ReadWriteThreadLock.Lock lock =
useSharedLock
? readWriteThreadLock.readLock()
: readWriteThreadLock.writeLock();
lock.lock();
try {
runnable.run();
} finally {
lock.unlock();
}
The key usage difference between ReadWriteThreadLock and a regular Java lock such as
ReentrantReadWriteLock is that ReadWriteThreadLock is itself not a lock object
(which threads are directly synchronized on), but only a proxy to the actual lock object.
Therefore, there could be multiple instances of ReadWriteThreadLock on the same lock
object.
Another distinction is that two lock objects are considered the same if one equals() the other. Thus, if the client uses a file as the lock object, in order for the paths to be correctly compared by equals(), it is important to normalize the file path first (e.g., using Path.normalize(), File.toPath().normalize(), or File.getCanonicalFile(); using File.getCanonicalPath() is not safe as it might cause incorrect comparisons on case-sensitivity filesystems like Windows).
This lock is reentrant.
This class is thread-safe.
| Modifier and Type | Class and Description |
|---|---|
static interface |
ReadWriteThreadLock.Lock |
| Constructor and Description |
|---|
ReadWriteThreadLock(java.lang.Object lockObject)
Creates a
ReadWriteThreadLock instance for the given lock object. |
| Modifier and Type | Method and Description |
|---|---|
ReadWriteThreadLock.Lock |
readLock()
Returns the lock used for reading.
|
ReadWriteThreadLock.Lock |
writeLock()
Returns the lock used for writing.
|
public ReadWriteThreadLock(@NonNull
java.lang.Object lockObject)
ReadWriteThreadLock instance for the given lock object. Threads will be
synchronized on the same lock object (two lock objects are the same if one equals() the
other).
The type (class) of the lock object must be loaded by a single class loader. Currently, this method requires the single class loader to be the bootstrap class loader.
If the client uses a file as the lock object, it is important to normalize the file path first (e.g., using Path.normalize(), File.toPath().normalize(), or File.getCanonicalFile(); using File.getCanonicalPath() is not safe as it might cause incorrect comparisons on case-sensitivity filesystems like Windows).
lockObject - the lock object, must be loaded by a single class loaderpublic ReadWriteThreadLock.Lock readLock()
public ReadWriteThreadLock.Lock writeLock()