writeLock possibly blocks
waiting for exclusive access, returning a stamp that can be used
in method unlockWrite to release the lock. Untimed and
timed versions of tryWriteLock are also provided. When
the lock is held in write mode, no read locks may be obtained,
and all optimistic read validations will fail.
readLock possibly blocks
waiting for non-exclusive access, returning a stamp that can be
used in method unlockRead to release the lock. Untimed
and timed versions of tryReadLock are also provided.
tryOptimisticRead
returns a non-zero stamp only if the lock is not currently held in
write mode. Method validate returns true if the lock has not
been acquired in write mode since obtaining a given stamp, in which
case all actions prior to the most recent write lock release
happen-before actions following the call to tryOptimisticRead.
This mode can be thought of as an extremely weak version of a
read-lock, that can be broken by a writer at any time. The use of
optimistic read mode for short read-only code segments often reduces
contention and improves throughput. However, its use is inherently
fragile. Optimistic read sections should only read fields and hold
them in local variables for later use after validation. Fields read
while in optimistic read mode may be wildly inconsistent, so usage
applies only when you are familiar enough with data representations to
check consistency and/or repeatedly invoke method validate().
For example, such steps are typically required when first reading an
object or array reference, and then accessing one of its fields,
elements or methods.
This class also supports methods that conditionally provide
conversions across the three modes. For example, method tryConvertToWriteLock attempts to "upgrade" a mode, returning
a valid write stamp if (1) already in writing mode (2) in reading
mode and there are no other readers or (3) in optimistic read mode
and the lock is available. The forms of these methods are designed to
help reduce some of the code bloat that otherwise occurs in
retry-based designs.
StampedLocks are designed for use as internal utilities in the development of thread-safe components. Their use relies on knowledge of the internal properties of the data, objects, and methods they are protecting. They are not reentrant, so locked bodies should not call other unknown methods that may try to re-acquire locks (although you may pass a stamp to other methods that can use or convert it). The use of read lock modes relies on the associated code sections being side-effect-free. Unvalidated optimistic read sections cannot call methods that are not known to tolerate potential inconsistencies. Stamps use finite representations, and are not cryptographically secure (i.e., a valid stamp may be guessable). Stamp values may recycle after (no sooner than) one year of continuous operation. A stamp held without use or validation for longer than this period may fail to validate correctly. StampedLocks are serializable, but always deserialize into initial unlocked state, so they are not useful for remote locking.
Like Semaphore, but unlike most
Lock implementations, StampedLocks have no notion of ownership.
Locks acquired in one thread can be released or converted in another.
The scheduling policy of StampedLock does not consistently prefer readers over writers or vice versa. All "try" methods are best-effort and do not necessarily conform to any scheduling or fairness policy. A zero return from any "try" method for acquiring or converting locks does not carry any information about the state of the lock; a subsequent invocation may succeed.
Because it supports coordinated usage across multiple lock
modes, this class does not directly implement the Lock or
ReadWriteLock interfaces. However, a StampedLock may be
viewed asReadLock(), asWriteLock(), or asReadWriteLock() in applications requiring only the associated
set of functionality.
Memory Synchronization. Methods with the effect of successfully locking in any mode have the same memory synchronization effects as a Lock action, as described in Chapter 17 of The Java Language Specification. Methods successfully unlocking in write mode have the same memory synchronization effects as an Unlock action. In optimistic read usages, actions prior to the most recent write mode unlock action are guaranteed to happen-before those following a tryOptimisticRead only if a later validate returns true; otherwise there is no guarantee that the reads between tryOptimisticRead and validate obtain a consistent snapshot.
Sample Usage. The following illustrates some usage idioms in a class that maintains simple two-dimensional points. The sample code illustrates some try/catch conventions even though they are not strictly needed here because no exceptions can occur in their bodies.
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
// an exclusively locked method
void move(double deltaX, double deltaY) {
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
// a read-only method
// upgrade from optimistic read to read lock
double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead();
try {
retryHoldingLock: for (;; stamp = sl.readLock()) {
if (stamp == 0L)
continue retryHoldingLock;
// possibly racy reads
double currentX = x;
double currentY = y;
if (!sl.validate(stamp))
continue retryHoldingLock;
return Math.hypot(currentX, currentY);
}
} finally {
if (StampedLock.isReadLockStamp(stamp))
sl.unlockRead(stamp);
}
}
// upgrade from optimistic read to write lock
void moveIfAtOrigin(double newX, double newY) {
long stamp = sl.tryOptimisticRead();
try {
retryHoldingLock: for (;; stamp = sl.writeLock()) {
if (stamp == 0L)
continue retryHoldingLock;
// possibly racy reads
double currentX = x;
double currentY = y;
if (!sl.validate(stamp))
continue retryHoldingLock;
if (currentX != 0.0 || currentY != 0.0)
break;
stamp = sl.tryConvertToWriteLock(stamp);
if (stamp == 0L)
continue retryHoldingLock;
// exclusive access
x = newX;
y = newY;
return;
}
} finally {
if (StampedLock.isWriteLockStamp(stamp))
sl.unlockWrite(stamp);
}
}
// upgrade read lock to write lock
void moveIfAtOrigin2(double newX, double newY) {
long stamp = sl.readLock();
try {
while (x == 0.0 && y == 0.0) {
long ws = sl.tryConvertToWriteLock(stamp);
if (ws != 0L) {
stamp = ws;
x = newX;
y = newY;
break;
}
else {
sl.unlockRead(stamp);
stamp = sl.writeLock();
}
}
} finally {
sl.unlock(stamp);
}
}
}
| Modifier and Type | Class and Description |
|---|---|
| pack-priv abstract static class | StampedLock.
CLH nodes |
| pack-priv static class | |
| pack-priv class | |
| pack-priv class | |
| pack-priv class | |
| pack-priv static class |
| Modifier and Type | Field and Description |
|---|---|
| private static final long | |
| pack-priv static final int | |
| private transient volatile StampedLock. | head
Head of CLH queue |
| private static final long | |
| private static final long | |
| private static final int | LG_READERS
The number of bits to use for reader count before overflowing |
| private static final long | ORIGIN
Initial value for lock state; avoids failure value zero. |
| private static final long | |
| private transient int | readerOverflow
extra reader count when state read count saturated |
| pack-priv transient StampedLock. | |
| pack-priv transient StampedLock. | |
| private static final long | |
| private static final long | |
| private static final long | |
| private static final long | |
| private static final long | |
| private transient volatile long | state
Lock sequence/state |
| private static final long | |
| private transient volatile StampedLock. | tail
Tail (last) of CLH queue |
| private static final long | |
| private static final Unsafe | |
| pack-priv static final int | |
| private static final long | |
| pack-priv transient StampedLock. |
| Access | Constructor and Description |
|---|---|
| public |
| Modifier and Type | Method and Description |
|---|---|
| private long | Returns: next state, or INTERRUPTEDtrue if should check interrupts and if so
return INTERRUPTED interruptible, boolean if true use timed waits timed, long the System.nanoTime value to timeout at (and return zero) time)See above for explanation. |
| private long | Returns: next state, or INTERRUPTEDtrue if should check interrupts and if so
return INTERRUPTED interruptible, boolean if true use timed waits timed, long the System.nanoTime value to timeout at (and return zero) time)For explanation, see above and AbstractQueuedSynchronizer internal documentation. |
| public Lock | Returns: the lockReturns a plain |
| public ReadWriteLock | Returns: the lockReturns a |
| public Lock | Returns: the lockReturns a plain |
| private void | cancelAcquire(StampedLock.
the waiter (may be null if not yet enqueued) nodeIf node non-null, forces cancel status and unsplices it from queue, wakes up any cowaiters, and possibly wakes up successor to recheck status. |
| private void | cancelCowaiter(StampedLock.
if non-null, the waiter node,if non-null, the node heading cowaiters list leaderIf node non-null, forces cancel status and unsplices from leader's cowaiters list unless/until it is also cancelled. |
| private boolean | |
| private boolean | |
| private void | cleanQueue()
Possibly repeatedly traverses from tail, unsplicing cancelled nodes until none are found. |
| private int | |
| public int | Returns: the number of read locks heldQueries the number of read locks held for this lock. |
| public static boolean | Returns: true if the stamp was returned by a successful
read-lock or write-lock operationa stamp returned by a previous StampedLock operation stamp)Tells whether a stamp represents holding a lock. |
| public static boolean | Returns: true if the stamp was returned by a successful
optimistic read operation, that is, a non-zero return from
tryOptimisticRead() or
tryConvertToOptimisticRead(long)a stamp returned by a previous StampedLock operation stamp)Tells whether a stamp represents a successful optimistic read. |
| public boolean | Returns: true if the lock is currently held non-exclusivelyReturns |
| public static boolean | Returns: true if the stamp was returned by a successful
read-lock operationa stamp returned by a previous StampedLock operation stamp)Tells whether a stamp represents holding a lock non-exclusively. |
| public boolean | Returns: true if the lock is currently held exclusivelyReturns |
| public static boolean | Returns: true if the stamp was returned by a successful
write-lock operationa stamp returned by a previous StampedLock operation stamp)Tells whether a stamp represents holding a lock exclusively. |
| public long | Returns: a read stamp that can be used to unlock or convert modeNon-exclusively acquires the lock, blocking if necessary until available. |
| public long | Returns: a read stamp that can be used to unlock or convert modeNon-exclusively acquires the lock, blocking if necessary until available or the current thread is interrupted. |
| private void | |
| private long | |
| private static void | signalCowaiters(StampedLock.
Removes and unparks all cowaiters of node, if it exists. |
| pack-priv static final void | signalNext(StampedLock.
Wakes up the successor of given node, if one exists, and unsets its WAITING status to avoid park race. |
| private long | spinLockOnOOME(boolean write, boolean interruptible, boolean timed, long time)
Fallback upon encountering OutOfMemoryErrors |
| public String | Returns: a string identifying this lock, as well as its lock stateOverrides java. Returns a string identifying this lock, as well as its lock state. |
| private long | |
| private long | |
| public long | Returns: a valid optimistic read stamp, or zero on failurea stamp stamp)If the lock state matches the given stamp then, atomically, if the stamp represents holding a lock, releases it and returns an observation stamp. |
| public long | Returns: a valid read stamp, or zero on failurea stamp stamp)If the lock state matches the given stamp, atomically performs one of the following actions. |
| public long | Returns: a valid write stamp, or zero on failurea stamp stamp)If the lock state matches the given stamp, atomically performs one of the following actions. |
| private long | Returns: new stamp on success, else zeroa reader overflow stamp: (s & ABITS) >= RFULL s)Tries to decrement readerOverflow. |
| private long | Returns: new stamp on success, else zeroa reader overflow stamp: (s & ABITS) >= RFULL s)Tries to increment readerOverflow by first setting state access bits value to RBITS, indicating hold of spinlock, then updating, then releasing. |
| private void | |
| public long | Returns: a valid optimistic read stamp, or zero if exclusively lockedReturns a stamp that can later be validated, or zero if exclusively locked. |
| public long | Returns: a read stamp that can be used to unlock or convert mode, or zero if the lock is not availableNon-exclusively acquires the lock if it is immediately available. |
| public long | Returns: a read stamp that can be used to unlock or convert mode, or zero if the lock is not availablethe maximum time to wait for the lock time, TimeUnit the time unit of the unit)time argumentNon-exclusively acquires the lock if it is available within the given time and the current thread has not been interrupted. |
| public boolean | Returns: true if the read lock was held, else falseReleases one hold of the read lock if it is held, without requiring a stamp value. |
| public boolean | Returns: true if the lock was held, else falseReleases the write lock if it is held, without requiring a stamp value. |
| public long | Returns: a write stamp that can be used to unlock or convert mode, or zero if the lock is not availableExclusively acquires the lock if it is immediately available. |
| public long | Returns: a write stamp that can be used to unlock or convert mode, or zero if the lock is not availablethe maximum time to wait for the lock time, TimeUnit the time unit of the unit)time argumentExclusively acquires the lock if it is available within the given time and the current thread has not been interrupted. |
| private void | unlinkCowaiter(StampedLock.
If leader exists, possibly repeatedly traverses cowaiters, unsplicing the given cancelled node until not found. |
| public void | unlock(long
a stamp returned by a lock operation stamp)If the lock state matches the given stamp, releases the corresponding mode of the lock. |
| public void | unlockRead(long
a stamp returned by a read-lock operation stamp)If the lock state matches the given stamp, releases the non-exclusive lock. |
| public void | unlockWrite(long
a stamp returned by a write-lock operation stamp)If the lock state matches the given stamp, releases the exclusive lock. |
| private static long | unlockWriteState(long
a write-locked state (or stamp) s)Returns an unlocked state, incrementing the version and avoiding special failure value 0L. |
| pack-priv final void | |
| pack-priv final void | |
| public boolean | Returns: true if the lock has not been exclusively acquired
since issuance of the given stamp; else falsea stamp stamp)Returns true if the lock has not been exclusively acquired since issuance of the given stamp. |
| public long | Returns: a write stamp that can be used to unlock or convert modeExclusively acquires the lock, blocking if necessary until available. |
| public long | Returns: a write stamp that can be used to unlock or convert modeExclusively acquires the lock, blocking if necessary until available or the current thread is interrupted. |