Serializable
public class StampedLock extends Object implements Serializable
writeLock()
possibly blocks waiting for exclusive access, returning a stamp that can be used in method unlockWrite(long)
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(long)
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(long)
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(long)
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);
}
}
}
Constructor | Description |
---|---|
StampedLock() |
Creates a new lock, initially in unlocked state. |
Modifier and Type | Method | Description |
---|---|---|
Lock |
asReadLock() |
Returns a plain Lock view of this StampedLock in which the Lock.lock() method is mapped to readLock() , and similarly for other methods. |
ReadWriteLock |
asReadWriteLock() |
Returns a ReadWriteLock view of this StampedLock in which the ReadWriteLock.readLock() method is mapped to asReadLock() , and ReadWriteLock.writeLock() to asWriteLock() . |
Lock |
asWriteLock() |
Returns a plain Lock view of this StampedLock in which the Lock.lock() method is mapped to writeLock() , and similarly for other methods. |
int |
getReadLockCount() |
Queries the number of read locks held for this lock. |
static boolean |
isLockStamp |
Tells whether a stamp represents holding a lock. |
static boolean |
isOptimisticReadStamp |
Tells whether a stamp represents a successful optimistic read. |
boolean |
isReadLocked() |
Returns true if the lock is currently held non-exclusively. |
static boolean |
isReadLockStamp |
Tells whether a stamp represents holding a lock non-exclusively. |
boolean |
isWriteLocked() |
Returns true if the lock is currently held exclusively. |
static boolean |
isWriteLockStamp |
Tells whether a stamp represents holding a lock exclusively. |
long |
readLock() |
Non-exclusively acquires the lock, blocking if necessary until available. |
long |
readLockInterruptibly() |
Non-exclusively acquires the lock, blocking if necessary until available or the current thread is interrupted. |
String |
toString() |
Returns a string identifying this lock, as well as its lock state. |
long |
tryConvertToOptimisticRead |
If the lock state matches the given stamp then, atomically, if the stamp represents holding a lock, releases it and returns an observation stamp. |
long |
tryConvertToReadLock |
If the lock state matches the given stamp, atomically performs one of the following actions. |
long |
tryConvertToWriteLock |
If the lock state matches the given stamp, atomically performs one of the following actions. |
long |
tryOptimisticRead() |
Returns a stamp that can later be validated, or zero if exclusively locked. |
long |
tryReadLock() |
Non-exclusively acquires the lock if it is immediately available. |
long |
tryReadLock |
Non-exclusively acquires the lock if it is available within the given time and the current thread has not been interrupted. |
boolean |
tryUnlockRead() |
Releases one hold of the read lock if it is held, without requiring a stamp value. |
boolean |
tryUnlockWrite() |
Releases the write lock if it is held, without requiring a stamp value. |
long |
tryWriteLock() |
Exclusively acquires the lock if it is immediately available. |
long |
tryWriteLock |
Exclusively acquires the lock if it is available within the given time and the current thread has not been interrupted. |
void |
unlock |
If the lock state matches the given stamp, releases the corresponding mode of the lock. |
void |
unlockRead |
If the lock state matches the given stamp, releases the non-exclusive lock. |
void |
unlockWrite |
If the lock state matches the given stamp, releases the exclusive lock. |
boolean |
validate |
Returns true if the lock has not been exclusively acquired since issuance of the given stamp. |
long |
writeLock() |
Exclusively acquires the lock, blocking if necessary until available. |
long |
writeLockInterruptibly() |
Exclusively acquires the lock, blocking if necessary until available or the current thread is interrupted. |
public StampedLock()
public long writeLock()
public long tryWriteLock()
public long tryWriteLock(long time, TimeUnit unit) throws InterruptedException
Lock.tryLock(long,TimeUnit)
.time
- the maximum time to wait for the lockunit
- the time unit of the time
argumentInterruptedException
- if the current thread is interrupted before acquiring the lockpublic long writeLockInterruptibly() throws InterruptedException
Lock.lockInterruptibly()
.InterruptedException
- if the current thread is interrupted before acquiring the lockpublic long readLock()
public long tryReadLock()
public long tryReadLock(long time, TimeUnit unit) throws InterruptedException
Lock.tryLock(long,TimeUnit)
.time
- the maximum time to wait for the lockunit
- the time unit of the time
argumentInterruptedException
- if the current thread is interrupted before acquiring the lockpublic long readLockInterruptibly() throws InterruptedException
Lock.lockInterruptibly()
.InterruptedException
- if the current thread is interrupted before acquiring the lockpublic long tryOptimisticRead()
public boolean validate(long stamp)
tryOptimisticRead()
or a locking method for this lock has no defined effect or result.stamp
- a stamptrue
if the lock has not been exclusively acquired since issuance of the given stamp; else falsepublic void unlockWrite(long stamp)
stamp
- a stamp returned by a write-lock operationIllegalMonitorStateException
- if the stamp does not match the current state of this lockpublic void unlockRead(long stamp)
stamp
- a stamp returned by a read-lock operationIllegalMonitorStateException
- if the stamp does not match the current state of this lockpublic void unlock(long stamp)
stamp
- a stamp returned by a lock operationIllegalMonitorStateException
- if the stamp does not match the current state of this lockpublic long tryConvertToWriteLock(long stamp)
stamp
- a stamppublic long tryConvertToReadLock(long stamp)
stamp
- a stamppublic long tryConvertToOptimisticRead(long stamp)
stamp
- a stamppublic boolean tryUnlockWrite()
true
if the lock was held, else falsepublic boolean tryUnlockRead()
true
if the read lock was held, else falsepublic boolean isWriteLocked()
true
if the lock is currently held exclusively.true
if the lock is currently held exclusivelypublic boolean isReadLocked()
true
if the lock is currently held non-exclusively.true
if the lock is currently held non-exclusivelypublic static boolean isWriteLockStamp(long stamp)
tryConvertToWriteLock(long)
, for example:
long stamp = sl.tryOptimisticRead();
try {
...
stamp = sl.tryConvertToWriteLock(stamp);
...
} finally {
if (StampedLock.isWriteLockStamp(stamp))
sl.unlockWrite(stamp);
}
stamp
- a stamp returned by a previous StampedLock operationtrue
if the stamp was returned by a successful write-lock operationpublic static boolean isReadLockStamp(long stamp)
tryConvertToReadLock(long)
, for example:
long stamp = sl.tryOptimisticRead();
try {
...
stamp = sl.tryConvertToReadLock(stamp);
...
} finally {
if (StampedLock.isReadLockStamp(stamp))
sl.unlockRead(stamp);
}
stamp
- a stamp returned by a previous StampedLock operationtrue
if the stamp was returned by a successful read-lock operationpublic static boolean isLockStamp(long stamp)
tryConvertToReadLock(long)
and tryConvertToWriteLock(long)
, for example:
long stamp = sl.tryOptimisticRead();
try {
...
stamp = sl.tryConvertToReadLock(stamp);
...
stamp = sl.tryConvertToWriteLock(stamp);
...
} finally {
if (StampedLock.isLockStamp(stamp))
sl.unlock(stamp);
}
stamp
- a stamp returned by a previous StampedLock operationtrue
if the stamp was returned by a successful read-lock or write-lock operationpublic static boolean isOptimisticReadStamp(long stamp)
stamp
- a stamp returned by a previous StampedLock operationtrue
if the stamp was returned by a successful optimistic read operation, that is, a non-zero return from tryOptimisticRead()
or tryConvertToOptimisticRead(long)
public int getReadLockCount()
public String toString()
"Unlocked"
or the String "Write-locked"
or the String "Read-locks:"
followed by the current number of read-locks held.public Lock asReadLock()
Lock
view of this StampedLock in which the Lock.lock()
method is mapped to readLock()
, and similarly for other methods. The returned Lock does not support a Condition
; method Lock.newCondition()
throws UnsupportedOperationException
.public Lock asWriteLock()
Lock
view of this StampedLock in which the Lock.lock()
method is mapped to writeLock()
, and similarly for other methods. The returned Lock does not support a Condition
; method Lock.newCondition()
throws UnsupportedOperationException
.public ReadWriteLock asReadWriteLock()
ReadWriteLock
view of this StampedLock in which the ReadWriteLock.readLock()
method is mapped to asReadLock()
, and ReadWriteLock.writeLock()
to asWriteLock()
.
© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/locks/StampedLock.html