Class StampedLock
- java.lang.Object
-
- co.paralleluniverse.strands.concurrent.StampedLock
-
- All Implemented Interfaces:
java.io.Serializable
public class StampedLock extends java.lang.Object implements java.io.Serializable
A capability-based lock with three modes for controlling read/write access. The state of a StampedLock consists of a version and mode. Lock acquisition methods return a stamp that represents and controls access with respect to a lock state; "try" versions of these methods may instead return the special value zero to represent failure to acquire access. Lock release and conversion methods require stamps as arguments, and fail if they do not match the state of the lock. The three modes are:- Writing. Method
writeLock()
possibly blocks waiting for exclusive access, returning a stamp that can be used in methodunlockWrite(long)
to release the lock. Untimed and timed versions oftryWriteLock
are also provided. When the lock is held in write mode, no read locks may be obtained, and all optimistic read validations will fail. - Reading. Method
readLock()
possibly blocks waiting for non-exclusive access, returning a stamp that can be used in methodunlockRead(long)
to release the lock. Untimed and timed versions oftryReadLock
are also provided. - Optimistic Reading. Method
tryOptimisticRead()
returns a non-zero stamp only if the lock is not currently held in write mode. Methodvalidate(long)
returns true if the lock has not been acquired in write mode since obtaining a given stamp. 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 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 mode may be wildly inconsistent, so usage applies only when you are familiar enough with data representations to check consistency and/or repeatedly invoke methodvalidate()
. 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 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 strand-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.
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
orReadWriteLock
interfaces. However, a StampedLock may be viewedasReadLock()
,asWriteLock()
, orasReadWriteLock()
in applications requiring only the associated set of functionality.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(); void move(double deltaX, double deltaY) { // an exclusively locked method long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } double distanceFromOriginV1() { // A read-only method long stamp; if ((stamp = sl.tryOptimisticRead()) != 0L) { // optimistic double currentX = x; double currentY = y; if (sl.validate(stamp)) return Math.sqrt(currentX * currentX + currentY * currentY); } stamp = sl.readLock(); // fall back to read lock try { double currentX = x; double currentY = y; return Math.sqrt(currentX * currentX + currentY * currentY); } finally { sl.unlockRead(stamp); } } double distanceFromOriginV2() { // combines code paths double currentX = 0.0, currentY = 0.0; for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) { try { currentX = x; currentY = y; } finally { if (sl.tryConvertToOptimisticRead(stamp) != 0L) // unlock or validate break; } } return Math.sqrt(currentX * currentX + currentY * currentY); } void moveIfAtOrigin(double newX, double newY) { // upgrade // Could instead start with optimistic, not read mode 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); } } }
- Since:
- 1.8
- See Also:
- Serialized Form
-
-
Constructor Summary
Constructors Constructor Description StampedLock()
Creates a new lock, initially in unlocked state.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description java.util.concurrent.locks.Lock
asReadLock()
Returns a plainLock
view of this StampedLock in which theLock.lock()
method is mapped toreadLock()
, and similarly for other methods.java.util.concurrent.locks.ReadWriteLock
asReadWriteLock()
Returns aReadWriteLock
view of this StampedLock in which theReadWriteLock.readLock()
method is mapped toasReadLock()
, andReadWriteLock.writeLock()
toasWriteLock()
.java.util.concurrent.locks.Lock
asWriteLock()
Returns a plainLock
view of this StampedLock in which theLock.lock()
method is mapped towriteLock()
, and similarly for other methods.boolean
isReadLocked()
Returns true if the lock is currently held non-exclusively.boolean
isWriteLocked()
Returns true if the lock is currently held 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 strand is interrupted.long
tryConvertToOptimisticRead(long stamp)
If the lock state matches the given stamp then, if the stamp represents holding a lock, releases it and returns an observation stamp.long
tryConvertToReadLock(long stamp)
If the lock state matches the given stamp, performs one of the following actions.long
tryConvertToWriteLock(long stamp)
If the lock state matches the given stamp, 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(long time, java.util.concurrent.TimeUnit unit)
Non-exclusively acquires the lock if it is available within the given time and the current strand 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(long time, java.util.concurrent.TimeUnit unit)
Exclusively acquires the lock if it is available within the given time and the current strand has not been interrupted.void
unlock(long stamp)
If the lock state matches the given stamp, releases the corresponding mode of the lock.void
unlockRead(long stamp)
If the lock state matches the given stamp, releases the non-exclusive lock.void
unlockWrite(long stamp)
If the lock state matches the given stamp, releases the exclusive lock.boolean
validate(long stamp)
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 strand is interrupted.
-
-
-
Method Detail
-
writeLock
@Suspendable public long writeLock()
Exclusively acquires the lock, blocking if necessary until available.- Returns:
- a stamp that can be used to unlock or convert mode
-
tryWriteLock
public long tryWriteLock()
Exclusively acquires the lock if it is immediately available.- Returns:
- a stamp that can be used to unlock or convert mode, or zero if the lock is not available
-
tryWriteLock
@Suspendable public long tryWriteLock(long time, java.util.concurrent.TimeUnit unit) throws java.lang.InterruptedException
Exclusively acquires the lock if it is available within the given time and the current strand has not been interrupted. Behavior under timeout and interruption matches that specified for methodLock.tryLock(long,TimeUnit)
.- Returns:
- a stamp that can be used to unlock or convert mode, or zero if the lock is not available
- Throws:
java.lang.InterruptedException
- if the current strand is interrupted before acquiring the lock
-
writeLockInterruptibly
@Suspendable public long writeLockInterruptibly() throws java.lang.InterruptedException
Exclusively acquires the lock, blocking if necessary until available or the current strand is interrupted. Behavior under interruption matches that specified for methodLock.lockInterruptibly()
.- Returns:
- a stamp that can be used to unlock or convert mode
- Throws:
java.lang.InterruptedException
- if the current strand is interrupted before acquiring the lock
-
readLock
@Suspendable public long readLock()
Non-exclusively acquires the lock, blocking if necessary until available.- Returns:
- a stamp that can be used to unlock or convert mode
-
tryReadLock
public long tryReadLock()
Non-exclusively acquires the lock if it is immediately available.- Returns:
- a stamp that can be used to unlock or convert mode, or zero if the lock is not available
-
tryReadLock
@Suspendable public long tryReadLock(long time, java.util.concurrent.TimeUnit unit) throws java.lang.InterruptedException
Non-exclusively acquires the lock if it is available within the given time and the current strand has not been interrupted. Behavior under timeout and interruption matches that specified for methodLock.tryLock(long,TimeUnit)
.- Returns:
- a stamp that can be used to unlock or convert mode, or zero if the lock is not available
- Throws:
java.lang.InterruptedException
- if the current strand is interrupted before acquiring the lock
-
readLockInterruptibly
@Suspendable public long readLockInterruptibly() throws java.lang.InterruptedException
Non-exclusively acquires the lock, blocking if necessary until available or the current strand is interrupted. Behavior under interruption matches that specified for methodLock.lockInterruptibly()
.- Returns:
- a stamp that can be used to unlock or convert mode
- Throws:
java.lang.InterruptedException
- if the current strand is interrupted before acquiring the lock
-
tryOptimisticRead
public long tryOptimisticRead()
Returns a stamp that can later be validated, or zero if exclusively locked.- Returns:
- a stamp, or zero if exclusively locked
-
validate
public boolean validate(long stamp)
Returns true if the lock has not been exclusively acquired since issuance of the given stamp. Always returns false if the stamp is zero. Always returns true if the stamp represents a currently held lock. Invoking this method with a value not obtained fromtryOptimisticRead()
or a locking method for this lock has no defined effect or result.- Returns:
- true if the lock has not been exclusively acquired since issuance of the given stamp; else false
-
unlockWrite
public void unlockWrite(long stamp)
If the lock state matches the given stamp, releases the exclusive lock.- Parameters:
stamp
- a stamp returned by a write-lock operation- Throws:
java.lang.IllegalMonitorStateException
- if the stamp does not match the current state of this lock
-
unlockRead
public void unlockRead(long stamp)
If the lock state matches the given stamp, releases the non-exclusive lock.- Parameters:
stamp
- a stamp returned by a read-lock operation- Throws:
java.lang.IllegalMonitorStateException
- if the stamp does not match the current state of this lock
-
unlock
public void unlock(long stamp)
If the lock state matches the given stamp, releases the corresponding mode of the lock.- Parameters:
stamp
- a stamp returned by a lock operation- Throws:
java.lang.IllegalMonitorStateException
- if the stamp does not match the current state of this lock
-
tryConvertToWriteLock
public long tryConvertToWriteLock(long stamp)
If the lock state matches the given stamp, performs one of the following actions. If the stamp represents holding a write lock, returns it. Or, if a read lock, if the write lock is available, releases the read lock and returns a write stamp. Or, if an optimistic read, returns a write stamp only if immediately available. This method returns zero in all other cases.- Parameters:
stamp
- a stamp- Returns:
- a valid write stamp, or zero on failure
-
tryConvertToReadLock
public long tryConvertToReadLock(long stamp)
If the lock state matches the given stamp, performs one of the following actions. If the stamp represents holding a write lock, releases it and obtains a read lock. Or, if a read lock, returns it. Or, if an optimistic read, acquires a read lock and returns a read stamp only if immediately available. This method returns zero in all other cases.- Parameters:
stamp
- a stamp- Returns:
- a valid read stamp, or zero on failure
-
tryConvertToOptimisticRead
public long tryConvertToOptimisticRead(long stamp)
If the lock state matches the given stamp then, if the stamp represents holding a lock, releases it and returns an observation stamp. Or, if an optimistic read, returns it if validated. This method returns zero in all other cases, and so may be useful as a form of "tryUnlock".- Parameters:
stamp
- a stamp- Returns:
- a valid optimistic read stamp, or zero on failure
-
tryUnlockWrite
public boolean tryUnlockWrite()
Releases the write lock if it is held, without requiring a stamp value. This method may be useful for recovery after errors.- Returns:
- true if the lock was held, else false
-
tryUnlockRead
public boolean tryUnlockRead()
Releases one hold of the read lock if it is held, without requiring a stamp value. This method may be useful for recovery after errors.- Returns:
- true if the read lock was held, else false
-
isWriteLocked
public boolean isWriteLocked()
Returns true if the lock is currently held exclusively.- Returns:
- true if the lock is currently held exclusively
-
isReadLocked
public boolean isReadLocked()
Returns true if the lock is currently held non-exclusively.- Returns:
- true if the lock is currently held non-exclusively
-
asReadLock
public java.util.concurrent.locks.Lock asReadLock()
Returns a plainLock
view of this StampedLock in which theLock.lock()
method is mapped toreadLock()
, and similarly for other methods. The returned Lock does not support aCondition
; methodLock.newCondition()
throwsUnsupportedOperationException
.- Returns:
- the lock
-
asWriteLock
public java.util.concurrent.locks.Lock asWriteLock()
Returns a plainLock
view of this StampedLock in which theLock.lock()
method is mapped towriteLock()
, and similarly for other methods. The returned Lock does not support aCondition
; methodLock.newCondition()
throwsUnsupportedOperationException
.- Returns:
- the lock
-
asReadWriteLock
public java.util.concurrent.locks.ReadWriteLock asReadWriteLock()
Returns aReadWriteLock
view of this StampedLock in which theReadWriteLock.readLock()
method is mapped toasReadLock()
, andReadWriteLock.writeLock()
toasWriteLock()
.- Returns:
- the lock
-
-