@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