- 所有已实现的接口:
-
Serializable
- 写入。 方法
writeLock()
可能会阻塞等待独占访问,返回一个可以在方法unlockWrite(long)
中使用的标记来释放锁。还提供了tryWriteLock
的无超时和有超时版本。当以写模式持有锁时,无法获取读锁,并且所有乐观读验证都将失败。 - 读取。 方法
readLock()
可能会阻塞等待非独占访问,返回一个可以在方法unlockRead(long)
中使用的标记来释放锁。还提供了tryReadLock
的无超时和有超时版本。 - 乐观读取。 方法
tryOptimisticRead()
仅在锁当前未以写模式持有时才返回非零标记。方法validate(long)
在自获得给定标记后未以写模式获取锁时返回true,在这种情况下,最近的写锁释放之前的所有操作都发生在调用tryOptimisticRead
之后的操作之前。这种模式可以被视为读锁的极弱版本,可以随时被写入者中断。在短的只读代码段中使用乐观读取模式通常会减少争用并提高吞吐量。但是,它的使用本质上是脆弱的。乐观读取部分应仅读取字段并将其保存在本地变量中以供稍后验证使用。在乐观读取模式下读取的字段可能极不一致,因此仅当您足够熟悉数据表示以检查一致性和/或重复调用方法validate()
时才适用。例如,在首次读取对象或数组引用,然后访问其字段、元素或方法时通常需要执行此类步骤。
此类还支持有条件地在三种模式之间提供转换的方法。例如,方法tryConvertToWriteLock(long)
尝试“升级”模式,如果(1)已经处于写入模式(2)处于读取模式且没有其他读取者或(3)处于乐观读取模式且锁可用,则返回有效的写入标记。这些方法的形式旨在帮助减少在基于重试的设计中否则会发生的一些代码膨胀。
StampedLocks设计用于作为开发线程安全组件的内部实用程序。它们不可重入,因此锁定的主体不应调用可能尝试重新获取锁的其他未知方法(尽管您可以将标记传递给其他可以使用或转换它的方法)。读锁模式的使用依赖于相关代码段是无副作用的。未经验证的乐观读取部分不能调用不知道能否容忍潜在不一致性的方法。标记使用有限表示,并且不是加密安全的(即,有效标记可能是可猜测的)。标记值可能在连续操作一年后(不早于)回收。长时间持有未使用或验证的标记可能导致验证不正确。StampedLocks是可序列化的,但始终反序列化为初始解锁状态,因此对于远程锁定而言并不实用。
与Semaphore
类似,但与大多数Lock
实现不同,StampedLocks没有所有权概念。在一个线程中获取的锁可以在另一个线程中释放或转换。
StampedLock的调度策略不一致地偏好读取者还是写入者。所有“尝试”方法都是尽力而为的,并且不一定符合任何调度或公平策略。从任何获取或转换锁的“尝试”方法返回零不携带有关锁状态的任何信息;后续调用可能成功。
由于它支持跨多个锁模式协调使用,因此此类不直接实现Lock
或ReadWriteLock
接口。但是,StampedLock可以在需要仅关联功能集的应用程序中被视为asReadLock()
、asWriteLock()
或asReadWriteLock()
。
内存同步。 具有成功锁定任何模式的效果的方法具有与Lock操作相同的内存同步效果,如The Java Language Specification第17章所述。成功以写模式解锁的方法具有与Unlock操作相同的内存同步效果。在乐观读取用法中,如果稍后的验证返回true,则最近的写模式解锁操作之前的操作保证发生在tryOptimisticRead之后的操作之前;否则,不能保证在tryOptimisticRead和validate之间的读取获得一致的快照。
示例用法。 以下示例说明了在维护简单二维点的类中的一些用法习惯用法。示例代码展示了一些try/catch约定,即使在这里严格来说不需要,因为它们的主体不会发生异常。
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
// 一个独占锁定的方法
void move(double deltaX, double deltaY) {
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
// 一个只读方法
// 从乐观读取升级到读锁
double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead();
try {
retryHoldingLock: for (;; stamp = sl.readLock()) {
if (stamp == 0L)
continue retryHoldingLock;
// 可能存在竞争读取
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);
}
}
// 从乐观读取升级到写锁
void moveIfAtOrigin(double newX, double newY) {
long stamp = sl.tryOptimisticRead();
try {
retryHoldingLock: for (;; stamp = sl.writeLock()) {
if (stamp == 0L)
continue retryHoldingLock;
// 可能存在竞争读取
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;
// 独占访问
x = newX;
y = newY;
return;
}
} finally {
if (StampedLock.isWriteLockStamp(stamp))
sl.unlockWrite(stamp);
}
}
// 从读锁升级到写锁
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);
}
}
}
- 参见Java语言规范:
-
17.4 内存模型
- 自Java版本:
- 1.8
- 另请参见:
-
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescription返回此StampedLock的ReadWriteLock
视图,其中ReadWriteLock.readLock()
方法映射到asReadLock()
,ReadWriteLock.writeLock()
方法映射到asWriteLock()
。int
查询此锁持有的读锁数量。static boolean
isLockStamp
(long stamp) 告诉一个标记是否代表持有锁。static boolean
isOptimisticReadStamp
(long stamp) 告诉一个标记是否代表成功的乐观读取。boolean
如果当前持有非独占锁,则返回true
。static boolean
isReadLockStamp
(long stamp) 告诉一个标记是否代表持有非独占锁。boolean
如果当前持有独占锁,则返回true
。static boolean
isWriteLockStamp
(long stamp) 告诉一个标记是否代表持有独占锁。long
readLock()
非独占地获取锁,必要时阻塞。long
非独占地获取锁,必要时阻塞,或者当前线程被中断。toString()
返回一个标识此锁及其锁状态的字符串。long
tryConvertToOptimisticRead
(long stamp) 如果锁状态与给定标记匹配,则原子地,如果标记代表持有锁,则释放它并返回一个观察标记。long
tryConvertToReadLock
(long stamp) 如果锁状态与给定标记匹配,则原子地执行以下操作之一。long
tryConvertToWriteLock
(long stamp) 如果锁状态与给定标记匹配,则以原子方式执行以下操作之一。long
返回一个稍后可以验证的标记,如果独占锁定则返回零。long
如果立即可用,则非独占地获取锁。long
tryReadLock
(long time, TimeUnit unit) 如果在给定时间内可用且当前线程未被中断,则非独占地获取锁。boolean
如果持有读锁,则释放一个持有的读锁,无需指定标记值。boolean
如果持有写锁,则释放写锁,无需指定标记值。long
如果立即可用,则独占地获取锁。long
tryWriteLock
(long time, TimeUnit unit) 如果在给定时间内可用且当前线程未被中断,则独占地获取锁。void
unlock
(long stamp) 如果锁状态与给定标记匹配,则释放锁的相应模式。void
unlockRead
(long stamp) 如果锁状态与给定标记匹配,则释放非独占锁。void
unlockWrite
(long stamp) 如果锁状态与给定标记匹配,则释放独占锁。boolean
validate
(long stamp) 如果自给定标记发放以来未独占获取锁,则返回true。long
如果需要,阻塞地独占地获取锁,直到可用。long
如果需要,阻塞地独占地获取锁,直到可用或当前线程被中断。
-
Constructor Details
-
StampedLock
public StampedLock()创建一个新的锁,初始状态为未锁定。
-
-
Method Details
-
writeLock
public long writeLock()如果需要,阻塞地独占地获取锁,直到可用。- 返回:
- 一个写标记,可用于解锁或转换模式
-
tryWriteLock
public long tryWriteLock()如果立即可用,则独占地获取锁。- 返回:
- 一个写标记,可用于解锁或转换模式,如果锁不可用则返回零
-
tryWriteLock
如果在给定时间内可用且当前线程未被中断,则独占地获取锁。超时和中断下的行为与方法Lock.tryLock(long,TimeUnit)
指定的行为相匹配。- 参数:
-
time
- 等待锁的最长时间 -
unit
-time
参数的时间单位 - 返回:
- 一个写标记,可用于解锁或转换模式,如果锁不可用则返回零
- 抛出:
-
InterruptedException
- 如果当前线程在获取锁之前被中断
-
writeLockInterruptibly
如果需要,阻塞地独占地获取锁,直到可用或当前线程被中断。中断下的行为与方法Lock.lockInterruptibly()
指定的行为相匹配。- 返回:
- 一个写标记,可用于解锁或转换模式
- 抛出:
-
InterruptedException
- 如果当前线程在获取锁之前被中断
-
readLock
public long readLock()如果需要,阻塞地非独占地获取锁,直到可用。- 返回:
- 一个读标记,可用于解锁或转换模式
-
tryReadLock
public long tryReadLock()如果立即可用,则非独占地获取锁。- 返回:
- 一个读标记,可用于解锁或转换模式,如果锁不可用则返回零
-
tryReadLock
如果在给定时间内可用且当前线程未被中断,则非独占地获取锁。超时和中断下的行为与方法Lock.tryLock(long,TimeUnit)
指定的行为相匹配。- 参数:
-
time
- 等待锁的最长时间 -
unit
-time
参数的时间单位 - 返回:
- 一个读标记,可用于解锁或转换模式,如果锁不可用则返回零
- 抛出:
-
InterruptedException
- 如果当前线程在获取锁之前被中断
-
readLockInterruptibly
如果需要,阻塞地非独占地获取锁,直到可用或当前线程被中断。中断下的行为与方法Lock.lockInterruptibly()
指定的行为相匹配。- 返回:
- 一个读标记,可用于解锁或转换模式
- 抛出:
-
InterruptedException
- 如果当前线程在获取锁之前被中断
-
tryOptimisticRead
public long tryOptimisticRead()返回一个稍后可以验证的标记,如果独占锁定则返回零。- 返回:
- 一个有效的乐观读标记,如果独占锁定则返回零
-
validate
public boolean validate(long stamp) 如果自给定标记发放以来未独占获取锁,则返回true。如果标记为零,则始终返回false。如果标记表示当前持有的锁,则始终返回true。使用不是从tryOptimisticRead()
或此锁的锁定方法获得的值调用此方法没有定义的效果或结果。- 参数:
-
stamp
- 一个标记 - 返回:
-
如果自给定标记发放以来未独占获取锁,则返回
true
;否则返回false
-
unlockWrite
public void unlockWrite(long stamp) 如果锁状态与给定标记匹配,则释放独占锁。- 参数:
-
stamp
- 由写锁操作返回的标记 - 抛出:
-
IllegalMonitorStateException
- 如果标记与此锁的当前状态不匹配
-
unlockRead
public void unlockRead(long stamp) 如果锁状态与给定标记匹配,则释放非独占锁。- 参数:
-
stamp
- 由读锁操作返回的标记 - 抛出:
-
IllegalMonitorStateException
- 如果标记与此锁的当前状态不匹配
-
unlock
public void unlock(long stamp) 如果锁状态与给定标记匹配,则释放锁的相应模式。- 参数:
-
stamp
- 由锁操作返回的标记 - 抛出:
-
IllegalMonitorStateException
- 如果标记与此锁的当前状态不匹配
-
tryConvertToWriteLock
public long tryConvertToWriteLock(long stamp) 如果锁状态与给定标记匹配,则以原子方式执行以下操作之一。如果标记表示持有写锁,则返回它。或者,如果是读锁,如果写锁可用,则释放读锁并返回写标记。或者,如果是乐观读,则仅在立即可用时返回写标记。此方法在所有其他情况下返回零。- 参数:
-
stamp
- 一个标记 - 返回:
- 一个有效的写标记,失败时返回零
-
tryConvertToReadLock
public long tryConvertToReadLock(long stamp) 如果锁状态与给定标记匹配,则以原子方式执行以下操作之一。如果标记表示持有写锁,则释放它并获取读锁。或者,如果是读锁,则返回它。或者,如果是乐观读,则仅在立即可用时获取读锁并返回读标记。此方法在所有其他情况下返回零。- 参数:
-
stamp
- 一个标记 - 返回:
- 一个有效的读标记,失败时返回零
-
tryConvertToOptimisticRead
public long tryConvertToOptimisticRead(long stamp) 如果锁状态与给定标记匹配,则以原子方式执行以下操作。如果标记表示持有锁,则释放它并返回一个观察标记。或者,如果是乐观读,则在验证后返回它。此方法在所有其他情况下返回零,因此可能作为一种“tryUnlock”形式有用。- 参数:
-
stamp
- 一个标记 - 返回:
- 一个有效的乐观读标记,失败时返回零
-
tryUnlockWrite
public boolean tryUnlockWrite()如果持有写锁,则释放它,无需指定标记值。此方法可能在错误后用于恢复。- 返回:
-
如果持有锁,则返回
true
,否则返回false
-
tryUnlockRead
public boolean tryUnlockRead()如果持有读锁,则释放一个持有的读锁,无需指定标记值。此方法可能在错误后用于恢复。- 返回:
-
如果持有读锁,则返回
true
,否则返回false
-
isWriteLocked
public boolean isWriteLocked()如果当前独占地持有锁,则返回true
。- 返回:
-
如果当前独占地持有锁,则返回
true
-
isReadLocked
public boolean isReadLocked()如果当前非独占地持有锁,则返回true
。- 返回:
-
如果当前非独占地持有锁,则返回
true
-
isWriteLockStamp
public static boolean isWriteLockStamp(long stamp) 告知一个标记是否表示独占地持有锁。此方法可能与tryConvertToWriteLock(long)
结合使用,例如:long stamp = sl.tryOptimisticRead(); try { ... stamp = sl.tryConvertToWriteLock(stamp); ... } finally { if (StampedLock.isWriteLockStamp(stamp)) sl.unlockWrite(stamp); }
- 参数:
-
stamp
- 由先前的StampedLock操作返回的标记 - 返回:
-
如果标记由成功的写锁操作返回,则返回
true
- 自:
- 10
-
isReadLockStamp
public static boolean isReadLockStamp(long stamp) 告知一个标记是否表示非独占地持有锁。此方法可能与tryConvertToReadLock(long)
结合使用,例如:long stamp = sl.tryOptimisticRead(); try { ... stamp = sl.tryConvertToReadLock(stamp); ... } finally { if (StampedLock.isReadLockStamp(stamp)) sl.unlockRead(stamp); }
- 参数:
-
stamp
- 由先前的StampedLock操作返回的标记 - 返回:
-
true
如果标记是由成功的读锁操作返回的 - 自JDK版本:
- 10
-
isLockStamp
public static boolean isLockStamp(long stamp) 告诉标记是否代表持有锁。这个方法可能与tryConvertToReadLock(long)
和tryConvertToWriteLock(long)
一起使用,例如:long stamp = sl.tryOptimisticRead(); try { ... stamp = sl.tryConvertToReadLock(stamp); ... stamp = sl.tryConvertToWriteLock(stamp); ... } finally { if (StampedLock.isLockStamp(stamp)) sl.unlock(stamp); }
- 参数:
-
stamp
- 由先前的StampedLock操作返回的标记 - 返回:
-
true
如果标记是由成功的读锁或写锁操作返回的 - 自JDK版本:
- 10
-
isOptimisticReadStamp
public static boolean isOptimisticReadStamp(long stamp) 告诉标记是否代表成功的乐观读取。- 参数:
-
stamp
- 由先前的StampedLock操作返回的标记 - 返回:
-
true
如果标记是由成功的乐观读取操作返回的,即,从tryOptimisticRead()
或tryConvertToOptimisticRead(long)
返回非零值 - 自JDK版本:
- 10
-
getReadLockCount
public int getReadLockCount()查询此锁保持的读锁数量。此方法设计用于监视系统状态,而不是用于同步控制。- 返回:
- 保持的读锁数量
-
toString
返回一个标识此锁及其锁状态的字符串。状态在括号中包括字符串"Unlocked"
或字符串"Write-locked"
或字符串"Read-locks:"
后跟当前持有的读锁数量。 -
asReadLock
返回此StampedLock的普通Lock
视图,其中Lock.lock()
方法映射到readLock()
,其他方法类似。返回的Lock不支持Condition
;方法Lock.newCondition()
抛出UnsupportedOperationException
。- 返回:
- 锁
-
asWriteLock
返回此StampedLock的普通Lock
视图,其中Lock.lock()
方法映射到writeLock()
,其他方法类似。返回的Lock不支持Condition
;方法Lock.newCondition()
抛出UnsupportedOperationException
。- 返回:
- 锁
-
asReadWriteLock
返回此StampedLock的ReadWriteLock
视图,其中ReadWriteLock.readLock()
方法映射到asReadLock()
,ReadWriteLock.writeLock()
映射到asWriteLock()
。- 返回:
- 锁
-