\file
ReadWriteLock
.d
\brief A
ReadWriteLock
maintains a pair of associated
locks, one for read-only operations and one for writing. The read
lock may be held simultaneously by multiple reader threads, so long
as there are no writers. The write lock is exclusive.
Written by Doug Lea with assistance from members of JCP JSR-166
Expert Group and released to the public domain, as explained at
http:
//creativecommons.org/licenses/publicdomain
Ported to D by Ben Hinkle.
Email comments and bug reports to ben.hinkle@gmail.com
revision 2.01
- interface
ReadWriteLock
;
- \class
ReadWriteLock
\brief A
ReadWriteLock
maintains a pair of associated
locks, one for read-only operations and one for writing. The read
lock may be held simultaneously by multiple reader threads, so long
as there are no writers. The write lock is exclusive.
A read-write lock allows for a greater level of concurrency in
accessing shared data, than that permitted by a mutual exclusion
lock. It exploits the fact that while only a single thread at a
time (a writer thread) can modify the shared data, in many
cases any number of threads can concurrently read the data (hence
reader threads). In theory, the increase in concurrency
permitted by the use of a read-write lock will lead to performance
improvements over the use of a mutual exclusion lock. In practice
this increase in concurrency will only be fully realized on a
multi-processor, and then only if the access patterns for the
shared data are suitable.
Whether or not a read-write lock will improve performance over the use
of a mutual exclusion lock depends on the frequency that the data is
read compared to being modified, the duration of the read and write
operations, and the contention for the data - that is, the number of
threads that will try to read or write the data at the same time.
For example, a collection that is initially populated with data and
thereafter infrequently modified, while being frequently searched
(such as a directory of some kind) is an ideal candidate for the use of
a read-write lock. However, if updates become frequent then the data
spends most of its time being exclusively locked and there is little, if any
increase in concurrency. Further, if the read operations are too short
the overhead of the read-write lock implementation (which is inherently
more complex than a mutual exclusion lock) can dominate the execution
cost, particularly as many read-write lock implementations still serialize
all threads through a small section of code. Ultimately, only profiling
and measurement will establish whether the use of a read-write lock is
suitable for your application.
@see ReentrantReadWriteLock
@see Lock
@see ReentrantLock
- abstract Lock
readLock
();
- Returns the lock used for reading.
\return the lock used for reading.
- abstract Lock
writeLock
();
- Returns the lock used for writing.
\return the lock used for writing.
- class
ReentrantReadWriteLock
: mango.locks.ReadWriteLock.ReadWriteLock;
- \class
ReentrantReadWriteLock
\brief An implementation of ReadWriteLock supporting similar
semantics to ReentrantLock.
This class has the following properties:
- Acquisition order
This class does not impose a reader or writer preference
ordering for lock access. However, it does support an optional
fairness policy. When constructed as fair, threads
contend for entry using an approximately arrival-order policy. When
the write lock is released either the longest-waiting single writer
will be assigned the write lock, or if there is a reader waiting
longer than any writer, the set of readers will be assigned the
read lock. When constructed as non-fair, the order of entry to the
lock need not be in arrival order. In either case, if readers are
active and a writer enters the lock then no subsequent readers will
be granted the read lock until after that writer has acquired and
released the write lock.
- Reentrancy
This lock allows both readers and writers to reacquire read or
write locks in the style of a ReentrantLock. Readers are not
allowed until all write locks held by the writing thread have been
released.
Additionally, a writer can acquire the read lock - but not vice-versa.
Among other applications, reentrancy can be useful when
write locks are held during calls or callbacks to methods that
perform reads under read locks.
If a reader tries to acquire the write lock it will never succeed.
- Lock downgrading
Reentrancy also allows downgrading from the write lock to a read lock,
by acquiring the write lock, then the read lock and then releasing the
write lock. However, upgrading from a read lock to the write lock, is
not possible.
- Condition support
The write lock provides a Condition implementation that behaves
in the same way, with respect to the write lock, as the Condition
implementation provided by ReentrantLock.newCondition does for
ReentrantLock. This Condition can, of course, only be used with
the write lock.
The read lock does not support a Condition and
readLock().newCondition() throws
UnsupportedOperationException.
- Instrumentation
This class supports methods to determine whether locks
are held or contended. These methods are designed for monitoring
system state, not for synchronization control.
Sample usages. Here is a code sketch showing how to exploit
reentrancy to perform lock downgrading after updating a cache (exception
handling is elided for simplicity):
class CachedData {
Object data;
bool cacheValid;
ReentrantReadWriteLock rwl;
this() {
rwl = new ReentrantReadWriteLock();
}
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// upgrade lock manually
rwl.readLock().unlock(); // must unlock first to obtain writelock
rwl.writeLock().lock();
if (!cacheValid) { // recheck
data = ...
cacheValid = true;
}
// downgrade lock
rwl.readLock().lock(); // reacquire read without giving up write lock
rwl.writeLock().unlock(); // unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}
ReentrantReadWriteLocks can be used to improve concurrency in some
uses of some kinds of collections. This is typically worthwhile
only when the collections are expected to be large, accessed by
more reader threads than writer threads, and entail operations with
overhead that outweighs synchronization overhead.
Implementation Notes
A reentrant write lock intrinsically defines an owner and can
only be released by the thread that acquired it. In contrast, in
this implementation, the read lock has no concept of ownership, and
there is no requirement that the thread releasing a read lock is
the same as the one that acquired it. However, this property is
not guaranteed to hold in future implementations of this class.
This lock supports a maximum of 65536 recursive write locks
and 65536 read locks. Attempts to exceed these limits result in
Error throws from locking methods.
- this(bool fair = false);
- Creates a new ReentrantReadWriteLock with
the given fairness policy.
\param fair true if this lock should use a fair ordering policy
- static int
sharedCount
(int c);
- Returns the number of shared holds represented in count
- static int
exclusiveCount
(int c);
- Returns the number of exclusive holds represented in count
- class
ReadLock
: mango.locks.Lock.Lock;
- The lock returned by method ReentrantReadWriteLock.readLock.
- this(ReentrantReadWriteLock lock);
- Constructor for use by subclasses
\param lock the outer lock object
- void
lock
();
- Acquires the shared
lock
.
Acquires the
lock
if it is not held exclusively by
another thread and returns immediately.
If the
lock
is held exclusively by another thread then
the current thread becomes disabled for thread scheduling
purposes and lies dormant until the
lock
has been acquired.
- bool
tryLock
();
- Acquires the shared lock only if it is not held exclusively by
another thread at the time of invocation.
Acquires the lock if it is not held exclusively by another
thread and returns immediately with the value
true. Even when this lock has been set to use a fair
ordering policy, a call to
tryLock
() will
immediately acquire the lock if it is available, whether or not
other threads are currently waiting for the lock. This
"barging" behavior can be useful in certain
circumstances, even though it breaks fairness. If you want to
honor the fairness setting for this lock, then use
tryLock
(0,
TimeUnit.SECONDS) which is almost equivalent (it also detects
interruption).
If the lock is held exclusively by another thread then
this method will return immediately with the value
false.
'return true if the lock was acquired.
- bool
tryLock
(long timeout, TimeUnit unit);
- Acquires the shared lock if it is not held exclusively by
another thread within the given waiting time.
Acquires the lock if it is not held exclusively by
another thread and returns immediately with the value
true. If this lock has been set to use a fair
ordering policy then an available lock will not be
acquired if any other threads are waiting for the
lock. This is in contrast to the
tryLock
()
method. If you want a timed
tryLock
that does
permit barging on a fair lock then combine the timed and
un-timed forms together:
if (lock.
tryLock
() || lock.
tryLock
(timeout, unit) ) { ... }
If the lock is held exclusively by another thread then the
current thread becomes disabled for thread scheduling
purposes and lies dormant until one of three things happens:
- The lock is acquired by the current thread; or
- The specified waiting time elapses
If the lock is acquired then the value true is
returned.
If the specified waiting time elapses then the value
false is returned. If the time is less than or
equal to zero, the method will not wait at all.
\param timeout the time to wait for the lock
\@param unit the time unit of the timeout argument
\return true if the lock was acquired.
- void
unlock
();
- Attempts to release this lock.
If the number of readers is now zero then the lock
is made available for other lock attempts.
- Condition
newCondition
();
- Throws UnsupportedOperationException because ReadLocks
do not support conditions.
\throws UnsupportedOperationException always
- char[]
toString
();
- Returns a string identifying this lock, as well as its lock state.
The state, in brackets, includes the String
"Read locks =" followed by the number of held
read locks.
\return a string identifying this lock, as well as its lock state.
- class
WriteLock
: mango.locks.Lock.Lock;
- The lock returned by method ReentrantReadWriteLock.writeLock
- this(ReentrantReadWriteLock lock);
- Constructor for use by subclasses
\param lock the outer lock object
- void
lock
();
- Acquire the
lock
.
Acquires the
lock
if it is not held by another thread
and returns immediately, setting the
lock
hold count to
one.
If the current thread already holds the
lock
then the
hold count is incremented by one and the method returns
immediately.
If the
lock
is held by another thread then the current
thread becomes disabled for thread scheduling purposes and
lies dormant until the
lock
has been acquired, at which
time the
lock
hold count is set to one.
- bool
tryLock
();
- Acquires the lock only if it is not held by another thread
at the time of invocation.
Acquires the lock if it is not held by another thread and
returns immediately with the value true, setting the
lock hold count to one. Even when this lock has been set to use
a fair ordering policy, a call to
tryLock
()
will immediately acquire the lock if it is available,
whether or not other threads are currently waiting for the
lock. This "barging" behavior can be useful in
certain circumstances, even though it breaks fairness. If you
want to honor the fairness setting for this lock, then use
.
tryLock
(0, TimeUnit.SECONDS) which is almost equivalent (it
also detects interruption).
If the current thread already holds this lock then the
hold count is incremented by one and the method returns
true.
If the lock is held by another thread then this method
will return immediately with the value false.
\return true if the lock was free and was acquired by the
current thread, or the lock was already held by the current thread; and
false otherwise.
- bool
tryLock
(long timeout, TimeUnit unit);
- Acquires the lock if it is not held by another thread
within the given waiting time.
Acquires the lock if it is not held by another thread
and returns immediately with the value true,
setting the lock hold count to one. If this lock has been
set to use a fair ordering policy then an available lock
will not be acquired if any other threads are
waiting for the lock. This is in contrast to the
tryLock
() method. If you want a timed
tryLock
that does permit barging on a fair lock then combine the
timed and un-timed forms together:
if (lock.
tryLock
() || lock.
tryLock
(timeout, unit) ) { ... }
If the current thread already holds this lock then the
hold count is incremented by one and the method returns
true.
If the lock is held by another thread then the current
thread becomes disabled for thread scheduling purposes and
lies dormant until one of three things happens:
- The lock is acquired by the current thread; or
- The specified waiting time elapses
If the lock is acquired then the value true is
returned and the lock hold count is set to one.
If the specified waiting time elapses then the value
false is returned. If the time is less than or
equal to zero, the method will not wait at all.
\param timeout the time to wait for the lock
\param unit the time unit of the timeout argument
\return true if the lock was free and was acquired
by the current thread, or the lock was already held by the
current thread; and false if the waiting time
elapsed before the lock could be acquired.
- void
unlock
();
- Attempts to release this lock.
If the current thread is the holder of this lock then
the hold count is decremented. If the hold count is now
zero then the lock is released.
- Condition
newCondition
();
- Returns a Condition instance for use with this Lock
instance. The semantics are like the semantics of the Condition
for a ReentrantLock.
\return the Condition object
- char[]
toString
();
- Returns a string identifying this lock, as well as its lock
state. The state, in brackets includes either the String
"Unlocked" or the String "Locked by"
followed by the Thread.
toString
of the owning thread.
\return a string identifying this lock, as well as its lock state.
- final bool
isFair
();
- Returns true if this lock has fairness set true.
@return true if this lock has fairness set true.
- protected Thread
getOwner
();
- Returns the thread that currently owns the exclusive lock, or
null if not owned. Note that the owner may be
momentarily null even if there are threads trying to
acquire the lock but have not yet done so. This method is
designed to facilitate construction of subclasses that provide
more extensive lock monitoring facilities.
@return the owner, or null if not owned.
- int
getReadLockCount
();
- Queries the number of read locks held for this lock. This
method is designed for use in monitoring system state, not for
synchronization control.
@return the number of read locks held.
- bool
isWriteLocked
();
- Queries if the write lock is held by any thread. This method is
designed for use in monitoring system state, not for
synchronization control.
@return true if any thread holds write lock and
false otherwise.
- bool
isWriteLockedByCurrentThread
();
- Queries if the write lock is held by the current thread.
@return true if current thread holds this lock and
false otherwise.
- int
getWriteHoldCount
();
- Queries the number of reentrant write holds on this lock by the
current thread. A writer thread has a hold on a lock for
each lock action that is not matched by an unlock action.
@return the number of holds on this lock by the current thread,
or zero if this lock is not held by the current thread.
- protected Thread[]
getQueuedWriterThreads
();
- Returns a collection containing threads that may be waiting to
acquire the write lock. Because the actual set of threads may
change dynamically while constructing this result, the returned
collection is only a best-effort estimate. The elements of the
returned collection are in no particular order. This method is
designed to facilitate construction of subclasses that provide
more extensive lock monitoring facilities.
@return the collection of threads
- protected Thread[]
getQueuedReaderThreads
();
- Returns a collection containing threads that may be waiting to
acquire the read lock. Because the actual set of threads may
change dynamically while constructing this result, the returned
collection is only a best-effort estimate. The elements of the
returned collection are in no particular order. This method is
designed to facilitate construction of subclasses that provide
more extensive lock monitoring facilities.
@return the collection of threads
- final bool
hasQueuedThreads
();
- Queries whether any threads are waiting to acquire. Note that
because cancellations may occur at any time, a true
return does not guarantee that any other thread will ever
acquire. This method is designed primarily for use in
monitoring of the system state.
@return true if there may be other threads waiting to acquire
the lock.
- final bool
hasQueuedThread
(Thread thread);
- Queries whether the given thread is waiting to acquire this
lock. Note that because cancellations may occur at any time, a
true return does not guarantee that this thread
will ever acquire. This method is designed primarily for use
in monitoring of the system state.
@param thread the thread
@return true if the given thread is queued waiting for this lock.
- final int
getQueueLength
();
- Returns an estimate of the number of threads waiting to
acquire. The value is only an estimate because the number of
threads may change dynamically while this method traverses
internal data structures. This method is designed for use in
monitoring of the system state, not for synchronization
control.
@return the estimated number of threads waiting for this lock
- protected Thread[]
getQueuedThreads
();
- Returns a collection containing threads that may be waiting to
acquire. Because the actual set of threads may change
dynamically while constructing this result, the returned
collection is only a best-effort estimate. The elements of the
returned collection are in no particular order. This method is
designed to facilitate construction of subclasses that provide
more extensive monitoring facilities.
@return the collection of threads
- bool
hasWaiters
(Condition condition);
- Queries whether any threads are waiting on the given condition
associated with the write lock. Note that because timeouts and
interrupts may occur at any time, a true return does
not guarantee that a future signal will awaken any
threads. This method is designed primarily for use in
monitoring of the system state.
@param condition the condition
@return true if there are any waiting threads.
- int
getWaitQueueLength
(Condition condition);
- Returns an estimate of the number of threads waiting on the
given condition associated with the write lock. Note that because
timeouts and interrupts may occur at any time, the estimate
serves only as an upper bound on the actual number of waiters.
This method is designed for use in monitoring of the system
state, not for synchronization control.
@param condition the condition
@return the estimated number of waiting threads.
- protected Thread[]
getWaitingThreads
(Condition condition);
- Returns a collection containing those threads that may be
waiting on the given condition associated with the write lock.
Because the actual set of threads may change dynamically while
constructing this result, the returned collection is only a
best-effort estimate. The elements of the returned collection
are in no particular order. This method is designed to
facilitate construction of subclasses that provide more
extensive condition monitoring facilities.
@param condition the condition
@return the collection of threads
- char[]
toString
();
- Returns a string identifying this lock, as well as its lock state.
The state, in brackets, includes the String "Write locks ="
follwed by the number of reentrantly held write locks, and the
String "Read locks =" followed by the number of held
read locks.
@return a string identifying this lock, as well as its lock state.
|