@Immutable
public final class ReadWriteThreadLock
extends java.lang.Object
ReentrantReadWriteLock used to synchronize threads within the same JVM,
even when classes (including this class) are loaded multiple times by different class loaders.
Motivation of ReadWriteThreadLock: 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 will 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 ReadWriteThreadLock 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.
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 differences between ReadWriteThreadLock and a regular Java lock such as
ReentrantReadWriteLock are:
ReadWriteThreadLock is itself not a lock object (which threads are directly
synchronized on), but a proxy to the actual lock object. Therefore, there could be multiple
instances of ReadWriteThreadLock on the same lock object.
This lock is reentrant, down-gradable, but not upgradable (similar to ReentrantReadWriteLock).
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.
|
java.lang.String |
toString() |
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 class of the lock object must be loaded only once, to avoid accidentally comparing two objects of the same class where the class is loaded multiple times by different class loaders, and therefore one never equals() the other.
If the client uses a file as the lock object, in order for this class to detect same
physical files via equals() the client needs to normalize the lock file's path when
constructing a ReadWriteThreadLock (preferably using Path.toRealPath(LinkOption...) with follow-link or File.getCanonicalFile(), as there
are subtle issues with other methods such as Path.normalize() or File.getCanonicalPath()). Path is slightly preferred to File for consistency
with ReadWriteProcessLock.
lockObject - the lock object, whose class must be loaded only once@NonNull public ReadWriteThreadLock.Lock readLock()
@NonNull public ReadWriteThreadLock.Lock writeLock()
public java.lang.String toString()
toString in class java.lang.Object