@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()