jsr166e
Class SequenceLock

java.lang.Object
  extended by jsr166e.SequenceLock
All Implemented Interfaces:
Serializable, Lock

public class SequenceLock
extends Object
implements Lock, Serializable

A reentrant mutual exclusion Lock in which each lock acquisition or release advances a sequence number. When the sequence number (accessible using getSequence()) is odd, the lock is held. When it is even (i.e., (lock.getSequence() & 1L) == 0L), the lock is released. Method awaitAvailability() can be used to await availability of the lock, returning its current sequence number. Sequence numbers (as well as reentrant hold counts) are of type long to ensure that they will not wrap around until hundreds of years of use under current processor rates. A SequenceLock can be created with a specified number of spins. Attempts to acquire the lock in method lock() will retry at least the given number of times before blocking. If not specified, a default, possibly platform-specific, value is used.

Except for the lack of support for specified fairness policies, or Condition objects, a SequenceLock can be used in the same way as ReentrantLock. It provides similar status and monitoring methods, such as isHeldByCurrentThread(). SequenceLocks may be preferable in contexts in which multiple threads invoke short read-only methods much more frequently than fully locked methods.

Methods awaitAvailability and getSequence can be used together to define (partially) optimistic read-only methods that are usually more efficient than ReadWriteLocks when they apply. These methods should in general be structured as loops that await lock availability, then read volatile fields into local variables (and may further read other values derived from these, for example the length of a volatile array), and retry if the sequence number changed while doing so. Alternatively, because awaitAvailability accommodates reentrancy, a method can retry a bounded number of times before switching to locking mode. While conceptually straightforward, expressing these ideas can be verbose. For example:

 class Point {
   private volatile double x, y;
   private final SequenceLock sl = new SequenceLock();

   // an exclusively locked method
   void move(double deltaX, double deltaY) {
     sl.lock();
     try {
       x += deltaX;
       y += deltaY;
     } finally {
       sl.unlock();
     }
   }

   // A read-only method
   double distanceFromOriginV1() {
     double currentX, currentY;
     long seq;
     do {
       seq = sl.awaitAvailability();
       currentX = x;
       currentY = y;
     } while (sl.getSequence() != seq); // retry if sequence changed
     return Math.sqrt(currentX * currentX + currentY * currentY);
   }

   // Uses bounded retries before locking
   double distanceFromOriginV2() {
     double currentX, currentY;
     long seq;
     int retries = RETRIES_BEFORE_LOCKING; // for example 8
     try {
       do {
         if (--retries < 0)
           sl.lock();
         seq = sl.awaitAvailability();
         currentX = x;
         currentY = y;
       } while (sl.getSequence() != seq);
     } finally {
       if (retries < 0)
         sl.unlock();
     }
     return Math.sqrt(currentX * currentX + currentY * currentY);
   }
 }

Since:
1.8
Author:
Doug Lea
See Also:
Serialized Form

Constructor Summary
SequenceLock()
          Creates an instance of SequenceLock with the default number of retry attempts to acquire the lock before blocking.
SequenceLock(int spins)
          Creates an instance of SequenceLock that will retry attempts to acquire the lock at least the given number times before blocking.
 
Method Summary
 long awaitAvailability()
          Returns the current sequence number when the lock is, or becomes, available.
 long getHoldCount()
          Queries the number of holds on this lock by the current thread.
protected  Thread getOwner()
          Returns the thread that currently owns this lock, or null if not owned.
protected  Collection<Thread> getQueuedThreads()
          Returns a collection containing threads that may be waiting to acquire this lock.
 int getQueueLength()
          Returns an estimate of the number of threads waiting to acquire this lock.
 long getSequence()
          Returns the current sequence number of this lock.
 boolean hasQueuedThread(Thread thread)
          Queries whether the given thread is waiting to acquire this lock.
 boolean hasQueuedThreads()
          Queries whether any threads are waiting to acquire this lock.
 boolean isHeldByCurrentThread()
          Queries if this lock is held by the current thread.
 boolean isLocked()
          Queries if this lock is held by any thread.
 void lock()
          Acquires the lock.
 void lockInterruptibly()
          Acquires the lock unless the current thread is interrupted.
 Condition newCondition()
          Throws UnsupportedOperationException.
 String toString()
          Returns a string identifying this lock, as well as its lock state.
 long tryAwaitAvailability(long timeout, TimeUnit unit)
          Returns the current sequence number if the lock is, or becomes, available within the specified waiting time.
 boolean tryLock()
          Acquires the lock only if it is not held by another thread at the time of invocation.
 boolean tryLock(long timeout, TimeUnit unit)
          Acquires the lock if it is not held by another thread within the given waiting time and the current thread has not been interrupted.
 void unlock()
          Attempts to release this lock.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Constructor Detail

SequenceLock

public SequenceLock()
Creates an instance of SequenceLock with the default number of retry attempts to acquire the lock before blocking.


SequenceLock

public SequenceLock(int spins)
Creates an instance of SequenceLock that will retry attempts to acquire the lock at least the given number times before blocking.

Method Detail

getSequence

public long getSequence()
Returns the current sequence number of this lock. The sequence number is advanced upon each acquire or release action. When this value is odd, the lock is held; when even, it is released.

Returns:
the current sequence number

awaitAvailability

public long awaitAvailability()
Returns the current sequence number when the lock is, or becomes, available. A lock is available if it is either released, or is held by the current thread. If the lock is not available, the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been released by some other thread.

Returns:
the current sequence number

tryAwaitAvailability

public long tryAwaitAvailability(long timeout,
                                 TimeUnit unit)
                          throws InterruptedException,
                                 TimeoutException
Returns the current sequence number if the lock is, or becomes, available within the specified waiting time.

If the lock is not available, the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happens:

Parameters:
timeout - the time to wait for availability
unit - the time unit of the timeout argument
Returns:
the current sequence number if the lock is available upon return from this method
Throws:
InterruptedException - if the current thread is interrupted
TimeoutException - if the lock was not available within the specified waiting time
NullPointerException - if the time unit is null

lock

public void lock()
Acquires the lock.

If the current thread already holds this lock then the hold count is incremented by one and the method returns immediately without incrementing the sequence number.

If this lock not held by another thread, this method increments the sequence number (which thus becomes an odd number), sets the lock hold count to one, and returns immediately.

If the lock is held by another thread then the current thread may retry acquiring this lock, depending on the spin count established in constructor. If the lock is still not acquired, the current thread becomes disabled for thread scheduling purposes and lies dormant until enabled by some other thread releasing the lock.

Specified by:
lock in interface Lock

lockInterruptibly

public void lockInterruptibly()
                       throws InterruptedException
Acquires the lock unless the current thread is interrupted.

If the current thread already holds this lock then the hold count is incremented by one and the method returns immediately without incrementing the sequence number.

If this lock not held by another thread, this method increments the sequence number (which thus becomes an odd number), sets the lock hold count to one, and returns immediately.

If the lock is held by another thread then the current thread may retry acquiring this lock, depending on the spin count established in constructor. If the lock is still not acquired, the current thread becomes disabled for thread scheduling purposes and lies dormant until one of two things happens:

If the lock is acquired by the current thread then the lock hold count is set to one and the sequence number is incremented.

If the current thread:

then InterruptedException is thrown and the current thread's interrupted status is cleared.

In this implementation, as this method is an explicit interruption point, preference is given to responding to the interrupt over normal or reentrant acquisition of the lock.

Specified by:
lockInterruptibly in interface Lock
Throws:
InterruptedException - if the current thread is interrupted

tryLock

public boolean tryLock()
Acquires the lock only if it is not held by another thread at the time of invocation.

If the current thread already holds this lock then the hold count is incremented by one and the method returns true without incrementing the sequence number.

If this lock not held by another thread, this method increments the sequence number (which thus becomes an odd number), sets the lock hold count to one, and returns true.

If the lock is held by another thread then this method returns false.

Specified by:
tryLock in interface Lock
Returns:
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

tryLock

public boolean tryLock(long timeout,
                       TimeUnit unit)
                throws InterruptedException
Acquires the lock if it is not held by another thread within the given waiting time and the current thread has not been interrupted.

If the current thread already holds this lock then the hold count is incremented by one and the method returns immediately without incrementing the sequence number.

If this lock not held by another thread, this method increments the sequence number (which thus becomes an odd number), sets the lock hold count to one, and returns immediately.

If the lock is held by another thread then the current thread may retry acquiring this lock, depending on the spin count established in constructor. If the lock is still not acquired, the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happens:

If the lock is acquired then the value true is returned and the lock hold count is set to one.

If the current thread:

then InterruptedException is thrown and the current thread's interrupted status is cleared.

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.

In this implementation, as this method is an explicit interruption point, preference is given to responding to the interrupt over normal or reentrant acquisition of the lock, and over reporting the elapse of the waiting time.

Specified by:
tryLock in interface Lock
Parameters:
timeout - the time to wait for the lock
unit - the time unit of the timeout argument
Returns:
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
Throws:
InterruptedException - if the current thread is interrupted
NullPointerException - if the time unit is null

unlock

public 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 sequence number is incremented (thus becoming an even number) and the lock is released. If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

Specified by:
unlock in interface Lock
Throws:
IllegalMonitorStateException - if the current thread does not hold this lock

newCondition

public Condition newCondition()
Throws UnsupportedOperationException. SequenceLocks do not support Condition objects.

Specified by:
newCondition in interface Lock
Throws:
UnsupportedOperationException

getHoldCount

public long getHoldCount()
Queries the number of holds on this lock by the current thread.

A thread has a hold on a lock for each lock action that is not matched by an unlock action.

The hold count information is typically only used for testing and debugging purposes.

Returns:
the number of holds on this lock by the current thread, or zero if this lock is not held by the current thread

isHeldByCurrentThread

public boolean isHeldByCurrentThread()
Queries if this lock is held by the current thread.

Returns:
true if current thread holds this lock and false otherwise

isLocked

public boolean isLocked()
Queries if this lock is held by any thread. This method is designed for use in monitoring of the system state, not for synchronization control.

Returns:
true if any thread holds this lock and false otherwise

getOwner

protected Thread getOwner()
Returns the thread that currently owns this lock, or null if not owned. When this method is called by a thread that is not the owner, the return value reflects a best-effort approximation of current lock status. For example, 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.

Returns:
the owner, or null if not owned

hasQueuedThreads

public final boolean hasQueuedThreads()
Queries whether any threads are waiting to acquire this lock. Note that because cancellations may occur at any time, a true return does not guarantee that any other thread will ever acquire this lock. This method is designed primarily for use in monitoring of the system state.

Returns:
true if there may be other threads waiting to acquire the lock

hasQueuedThread

public final boolean 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 lock. This method is designed primarily for use in monitoring of the system state.

Parameters:
thread - the thread
Returns:
true if the given thread is queued waiting for this lock
Throws:
NullPointerException - if the thread is null

getQueueLength

public final int getQueueLength()
Returns an estimate of the number of threads waiting to acquire this lock. 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.

Returns:
the estimated number of threads waiting for this lock

getQueuedThreads

protected Collection<Thread> getQueuedThreads()
Returns a collection containing threads that may be waiting to acquire this 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 monitoring facilities.

Returns:
the collection of threads

toString

public String 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 name of the owning thread.

Overrides:
toString in class Object
Returns:
a string identifying this lock, as well as its lock state


Copyright © 2009-2012. All Rights Reserved.