\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.

    :: page rendered by CandyDoc