public class SequenceLock extends Object implements Lock, Serializable
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);
}
}| Constructor and Description |
|---|
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 of times
before blocking. |
| Modifier and Type | Method and Description |
|---|---|
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.
|
public SequenceLock()
SequenceLock with the default
number of retry attempts to acquire the lock before blocking.public SequenceLock(int spins)
SequenceLock that will retry
attempts to acquire the lock at least the given number of times
before blocking.spins - the number of times before blockingpublic long getSequence()
public long awaitAvailability()
public long tryAwaitAvailability(long timeout,
TimeUnit unit)
throws InterruptedException,
TimeoutException
If the lock is not available, the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happens:
InterruptedException.
TimeoutException.
timeout - the time to wait for availabilityunit - the time unit of the timeout argumentInterruptedException - if the current thread is interruptedTimeoutException - if the lock was not available within
the specified waiting timeNullPointerException - if the time unit is nullpublic void 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.
public void lockInterruptibly()
throws InterruptedException
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:
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.
lockInterruptibly in interface LockInterruptedException - if the current thread is interruptedpublic boolean tryLock()
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.
public boolean tryLock(long timeout,
TimeUnit unit)
throws InterruptedException
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:
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.
tryLock in interface Locktimeout - the time to wait for the lockunit - the time unit of the timeout argumenttrue 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 acquiredInterruptedException - if the current thread is interruptedNullPointerException - if the time unit is nullpublic void unlock()
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.
unlock in interface LockIllegalMonitorStateException - if the current thread does not
hold this lockpublic Condition newCondition()
newCondition in interface LockUnsupportedOperationException - alwayspublic long getHoldCount()
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.
public boolean isHeldByCurrentThread()
true if current thread holds this lock and
false otherwisepublic boolean isLocked()
true if any thread holds this lock and
false otherwiseprotected Thread getOwner()
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.null if not ownedpublic final boolean hasQueuedThreads()
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.true if there may be other threads waiting to
acquire the lockpublic final boolean hasQueuedThread(Thread thread)
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.thread - the threadtrue if the given thread is queued waiting for this lockNullPointerException - if the thread is nullpublic final int getQueueLength()
protected Collection<Thread> getQueuedThreads()
Copyright © 2013. All rights reserved.