Module java.base

Class StampedLock

java.lang.Object
java.util.concurrent.locks.StampedLock
所有已实现的接口:
Serializable

public class StampedLock extends Object implements Serializable
一个具有三种模式用于控制读/写访问的基于能力的锁。StampedLock的状态由版本和模式组成。锁获取方法返回一个代表并控制与锁状态相关的访问的标记;这些方法的“尝试”版本可能返回特殊值零来表示未能获取访问权限。锁释放和转换方法需要标记作为参数,并且如果它们与锁的状态不匹配则失败。三种模式是:
  • 写入。 方法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的调度策略不一致地偏好读取者还是写入者。所有“尝试”方法都是尽力而为的,并且不一定符合任何调度或公平策略。从任何获取或转换锁的“尝试”方法返回零不携带有关锁状态的任何信息;后续调用可能成功。

由于它支持跨多个锁模式协调使用,因此此类不直接实现LockReadWriteLock接口。但是,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

    Constructors
    Constructor
    Description
    创建一个新的锁,最初处于解锁状态。
  • Method Summary

    Modifier and Type
    Method
    Description
    返回此StampedLock的普通Lock视图,其中Lock.lock()方法映射到readLock(),其他方法类似。
    返回此StampedLock的ReadWriteLock视图,其中ReadWriteLock.readLock()方法映射到asReadLock()ReadWriteLock.writeLock()方法映射到asWriteLock()
    返回此StampedLock的普通Lock视图,其中Lock.lock()方法映射到writeLock(),其他方法类似。
    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
    非独占地获取锁,必要时阻塞。
    long
    非独占地获取锁,必要时阻塞,或者当前线程被中断。
    返回一个标识此锁及其锁状态的字符串。
    long
    如果锁状态与给定标记匹配,则原子地,如果标记代表持有锁,则释放它并返回一个观察标记。
    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
    如果需要,阻塞地独占地获取锁,直到可用或当前线程被中断。

    Methods declared in class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
  • Constructor Details

    • StampedLock

      public StampedLock()
      创建一个新的锁,初始状态为未锁定。
  • Method Details

    • writeLock

      public long writeLock()
      如果需要,阻塞地独占地获取锁,直到可用。
      返回:
      一个写标记,可用于解锁或转换模式
    • tryWriteLock

      public long tryWriteLock()
      如果立即可用,则独占地获取锁。
      返回:
      一个写标记,可用于解锁或转换模式,如果锁不可用则返回零
    • tryWriteLock

      public long tryWriteLock(long time, TimeUnit unit) throws InterruptedException
      如果在给定时间内可用且当前线程未被中断,则独占地获取锁。超时和中断下的行为与方法Lock.tryLock(long,TimeUnit)指定的行为相匹配。
      参数:
      time - 等待锁的最长时间
      unit - time参数的时间单位
      返回:
      一个写标记,可用于解锁或转换模式,如果锁不可用则返回零
      抛出:
      InterruptedException - 如果当前线程在获取锁之前被中断
    • writeLockInterruptibly

      public long writeLockInterruptibly() throws InterruptedException
      如果需要,阻塞地独占地获取锁,直到可用或当前线程被中断。中断下的行为与方法Lock.lockInterruptibly()指定的行为相匹配。
      返回:
      一个写标记,可用于解锁或转换模式
      抛出:
      InterruptedException - 如果当前线程在获取锁之前被中断
    • readLock

      public long readLock()
      如果需要,阻塞地非独占地获取锁,直到可用。
      返回:
      一个读标记,可用于解锁或转换模式
    • tryReadLock

      public long tryReadLock()
      如果立即可用,则非独占地获取锁。
      返回:
      一个读标记,可用于解锁或转换模式,如果锁不可用则返回零
    • tryReadLock

      public long tryReadLock(long time, TimeUnit unit) throws InterruptedException
      如果在给定时间内可用且当前线程未被中断,则非独占地获取锁。超时和中断下的行为与方法Lock.tryLock(long,TimeUnit)指定的行为相匹配。
      参数:
      time - 等待锁的最长时间
      unit - time参数的时间单位
      返回:
      一个读标记,可用于解锁或转换模式,如果锁不可用则返回零
      抛出:
      InterruptedException - 如果当前线程在获取锁之前被中断
    • readLockInterruptibly

      public long readLockInterruptibly() throws InterruptedException
      如果需要,阻塞地非独占地获取锁,直到可用或当前线程被中断。中断下的行为与方法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

      public String toString()
      返回一个标识此锁及其锁状态的字符串。状态在括号中包括字符串 "Unlocked"或字符串"Write-locked"或字符串"Read-locks:"后跟当前持有的读锁数量。
      覆盖:
      toString 在类 Object
      返回:
      一个标识此锁及其锁状态的字符串
    • asReadLock

      public Lock asReadLock()
      返回此StampedLock的普通Lock视图,其中Lock.lock()方法映射到readLock(),其他方法类似。返回的Lock不支持Condition;方法Lock.newCondition()抛出UnsupportedOperationException
      返回:
    • asWriteLock

      public Lock asWriteLock()
      返回此StampedLock的普通Lock视图,其中Lock.lock()方法映射到writeLock(),其他方法类似。返回的Lock不支持Condition;方法Lock.newCondition()抛出UnsupportedOperationException
      返回:
    • asReadWriteLock

      public ReadWriteLock asReadWriteLock()
      返回此StampedLock的ReadWriteLock视图,其中ReadWriteLock.readLock()方法映射到asReadLock()ReadWriteLock.writeLock()映射到asWriteLock()
      返回: