前言
相关系列
- 《Java & Lock & 目录》
- 《Java & Lock & StampedLock & 源码》
- 《Java & Lock & StampedLock & 总结》
- 《Java & Lock & StampedLock & 问题》
涉及内容
源码
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
*
*
*
*
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package juc.locks;
import juc.TimeUnit;
import 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:
* 一种随三种模式来控制读/写访问的基础能力锁。邮戳锁的状态与版本/模式一致。锁获取方法返回一个代表/控制关于
* 锁状态访问的邮戳;这些方法的"尝试"版本可能返回特殊值0代表获取访问失败。锁释放/反转方法会获取邮戳作为参数,
* 并做如果没有匹配的锁状态会失败。这三种模式如下:
* <ul>
*
* <li><b>Writing.</b> Method {@link #writeLock} possibly blocks waiting for exclusive access, returning a stamp that
* can be used in method {@link #unlockWrite} to release the lock. Untimed and timed versions of {@code 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. </li>
* 写。写锁方法可能为了排它访问而阻塞等待,并返回一个可用于unlockWrite方法的邮戳来释放锁。tryWriteLock的非定
* 时/定时版本也提供。当锁持有写模式时,没有读锁可被获取,并且所有乐观读校验将失败。
* <li><b>Reading.</b> Method {@link #readLock} possibly blocks waiting for non-exclusive access, returning a stamp
* that can be used in method {@link #unlockRead} to release the lock. Untimed and timed versions of
* {@code tryReadLock} are also provided. </li>
* 读。readLock方法可能为了非排他访问而阻塞等待,返回一个可用于unlockRead方法的邮戳以释放锁。tryReadLock的
* 非定时/定时版本也提供。
* <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead} returns a non-zero stamp only if the lock is not
* currently held in write mode. Method {@link #validate} 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 method {@code 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. </li>
* 乐观读取。tryOptimisticRead方法只在锁当前未被写模式持有的情况下返回非0的邮戳。如果锁从获取一个指定邮戳开
* 始未曾在写模式中被获取则validate方法会返回true。该模式可以被认为是读锁的极致弱化版本,它可以在任意时间写
* 线程破坏。乐观模式常用为了减少竞争及改善吞吐量而在短只读代码中使用。此外,它的使用是固有易碎的。乐观读
* 取部分应该只读取字段,并为了在校验后持有使用而在本地变量中持有它们。字段读取在乐观模式中可能疯狂地不一
* 致,所以用法只在你足够熟悉数据表示(快照)来检查一致性并/或 重复调用validate()方法是应用。例如,该步骤通
* 常用于在首次读取一个对象或数组引用时访问它们字段/元素/方法的一个。
* </ul>
* <p>
* This class also supports methods that conditionally provide conversions across the three modes. For example,
* method {@link #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 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-baseddesigns.
* 该类还支持条件性提供转换访问三种模式的方法。例如:tryConvertToWriteLock()方法尝试"升级"模式,如果(1)在等待
* 模式中,或者(2)在准备模式并且没有其它读线程,或者(3)在乐观模式并且锁可用则返回一个合法的写邮戳。这些方法
* 格式被设计帮助减少代码在基础重试设计中发生的膨胀。
* <p>
* 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.
* 邮戳锁被设计用于在线程安全组件中作为内部工具使用。它的使用依赖与数据/对象/方法所保护的内部属性知识。它们
* 不重入,所以锁体不应该调用其它可能重获取锁(尽管你可能通过一个邮戳前往其它可使用或转换它的方法)的未知方
* 法。读锁模式的使用依赖相关的代码段没有副作用。未校验的乐观读取段无法调用未知的方法来容忍潜在的非一致性。
* 邮戳使用有限的代理,并且不密码安全(即:一个合法的邮戳是可猜测的)。邮戳值可能在持续操作的(不会快于)一
* 年后再被利用。一个邮戳持有比当前周期更长的时间未使用或校验则可能被正确校验失败。邮戳锁是序列化的,但是经
* 常反序列化为初始为加锁的状态,所以它们并不用于远程加锁。
* <p>
* 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.
* 邮戳锁的调度策略是不一致地,更偏向于读线程而不是写线程(或反过来)。所有"尝试"方法会尽最大努力,并且没有
* 必要遵守任意调度/公平策略。从任意获取/转换锁的"尝试"方法中返回的0不会携带任何关于锁状态的信息;随后调用
* 可能成功。
* <p>
* Because it supports coordinated usage across multiple lock modes, this class does not directly implement the
* {@link Lock} or {@link ReadWriteLock} interfaces. However, a StampedLock may be viewed {@link #asReadLock()},
* {@link #asWriteLock()}, or {@link #asReadWriteLock()} in applications requiring only the associated set of
* functionality.
* 该类不直接继承实现锁/读写锁接口,因为它支持访问多锁模式的协调用法。此外,一个邮戳锁可能在应用中查看了
* asReadLock()、asWriteLock()、asReadWriteLock()方法而只获取函数相关的集合。
* <p>
* <b>Sample Usage.</b> 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.<br>
* 简单用法。接下来说明某些在类中保持简单双维度的用法风格。简单代码以try/catch习惯举例说明,即使它们不完全
* 需要,因为无异常在它们的内部中发生。
* <pre>{@code
* 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 distanceFromOrigin() {
* // A read-only method
* // 一个只读方法
* long stamp = sl.tryOptimisticRead();
* double currentX = x, currentY = y;
* // ---- 校验是否执行过写操作。
* if (!sl.validate(stamp)) {
* stamp = sl.readLock();
* try {
* // ---- 读操作。
* currentX = x;
* currentY = y;
* } finally {
* sl.unlockRead(stamp);
* }
* }
* 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);
* }
* }
* }}</pre>
*
* @author Doug Lea
* @since 1.8
*/
public class StampedLock implements Serializable {
/*
* Algorithmic notes:
* 算法简介:
* The design employs elements of Sequence locks (as used in linux kernels; see
* Lameter's http://www.lameter.com/gelato2005.pdf and elsewhere; see Boehm's
* http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html) and Ordered RW locks (see Shirako et al
* http://dl.acm.org/citation.cfm?id=2312015)
* 该设计使用顺序锁/有序读写锁的元素。
* Conceptually, the primary state of the lock includes a sequence number that is odd when write-locked and even
* otherwise. However, this is offset by a reader count that is non-zero when read-locked. The read count is
* ignored when validating "optimistic" seqlock-reader-style stamps. Because we must use a small finite number of
* bits (currently 7) for readers, a supplementary reader overflow word is used when the number of readers exceeds
* the count field. We do this by treating the max reader count value (RBITS) as a spinlock protecting overflow
* updates.
* 概念上,当写锁被锁时,该锁的优先状态包括一个奇怪的顺序数,即使不考虑其它情况也是如此。此外,当读锁被
* 锁时,该顺序数将被一个非零的读线程总数所抵消。当检查"乐观" 顺序锁读线程风格邮戳时,读总数将被遗忘。因
* 为我们必须为读线程使用一个小而有限的比特(当前为7)数量。当读线程数量超过字段总数时,一个补充读线程
* 溢出单词会被使用。我们通过把最大读线程总数值看做一个自旋锁来保护移除更新。
* Waiters use a modified form of CLH lock used in AbstractQueuedSynchronizer (see its internal documentation for
* a fuller account), where each node is tagged (field mode) as either a reader or writer. Sets of waiting readers
* are grouped (linked) under a common node (field cowait) so act as a single node with respect to most CLH
* mechanics. By virtue of the queue structure, wait nodes need not actually carry sequence numbers; we know
* each is greater than its predecessor. This simplifies the scheduling policy to a mainly-FIFO scheme that
* incorporates elements of Phase-Fair locks (see Brandenburg & Anderson, especially
* http://www.cs.unc.edu/~bbb/diss/). In particular, we use the phase-fair anti-barging rule: If an incoming reader
* arrives while read lock is held but there is a queued writer, this incoming reader is queued. (This rule is
* responsible for some of the complexity of method acquireRead, but without it, the lock becomes highly unfair.)
* Method release does not (and sometimes cannot) itself wake up cowaiters. This is done by the primary thread,
* but helped by any other threads with nothing better to do in methods acquireRead and acquireWrite.
* 等待者使用一个用于AQS的同步队列锁的修改格式,每个被标记 (字段模式)的节点即是读线程也是写线程。等待
* 中的读线程集合会在一个公共节点(字段cowait)下被分组,所以可以在CLH机制方面充当一个单节点。借助队列结
* 构的优点,等待节点实际上不需要携带顺序数,因为我们知道每个节点都大于它的前驱节点。这类似于包含阶段公平锁
* 元素的FIFO体系的调度策略。特别地,我们使用阶段公平反对碰撞规则:如果一个读线程在读锁被持有期间到达但存
* 在排队的等待者,该到来的读线程将排队。(该规则为某些获取读方法的复杂性负责,但不包括锁变得更高级不公平
* 的情况。)方法释放不会(以及有时不会)自我唤醒等待者。这通过主线程执行,但也通过在获取读/获取些方法中
* 其它一些没有更好的事情可做的线程帮助。
* These rules apply to threads actually queued. All tryLock forms opportunistically try to acquire locks regardless
* of preference rules, and so may "barge" their way in. Randomized spinning is used in the acquire methods to reduce
* (increasingly expensive) context switching while also avoiding sustained memory thrashing among many threads.
* We limit spins to the head of queue. A thread spin-waits up to SPINS times (where each iteration decreases spin
* count with 50% probability) before blocking. If, upon wakening it fails to obtain lock, and is still (or becomes) the
* first waiting thread (which indicates that some other thread barged and obtained lock), it escalates spins (up to
* MAX_HEAD_SPINS) to reduce the likelihood of continually losing to barging threads.
* 这些规则引用于实际排队的线程。所有tryLock方法格式都会适时地尝试获取锁而不顾偏向规则,并且可能"碰撞"它们的
* 入口。随机的自旋被用于在获取方法中减少(逐渐昂贵)上下文切换,还避免在一些线程中被持续的内存击打。我们限
* 制队列的自旋。一个线程在阻塞前自旋等待不超过SPINS次(每次迭代有50%的可能性减少自旋总数)。如果,唤醒线
* 程后获取锁失败,并且依然(获取成为)是首个等待中的线程(这意味着有其它线程碰撞并获取锁),它会加剧自旋(
* 不超过MAX_HEAD_SPINS)以减少继续丢失碰撞中的线程的可能性。
* Nearly all of these mechanics are carried out in methods acquireWrite and acquireRead, that, as typical of such
* code, sprawl out because actions and retries rely on consistent sets of locally cached reads.
* 这些机制几乎都在获取读/写方法中完成,这被作为代码典型,因为活动/重试依赖于一致的本地缓存集的的读取,所
* 以会拓展。
* As noted in Boehm's paper (above), sequence validation (mainly method validate()) requires stricter ordering rules
* than apply to normal volatile reads (of "state"). To force orderings of reads before a validation and the validation
* itself in those cases where this is not already forced, we use Unsafe.loadFence.
* 在Boehm资料(之上)的注解中,顺序检查(主要指validate()方法)要求顺序规则比应用于常规(状态)读取的检查更
* 加严格。为了在验证之前强制读取顺序,以及在验证本身没有强制的情况下,我们使用了Unsafe.loadFence。
* The memory layout keeps lock state and queue pointers together (normally on the same cache line). This usually
* works well for read-mostly loads. In most other cases, the natural tendency of adaptive-spin CLH locks to reduce
* memory contention lessens motivation to further spread out contended locations, but might be subject to future
* improvements.
* 内部布局一同保持锁状态及队列指针(通常在相同的内存行)。这通常适用于读为主的负载。在大多数其他情况下,
* 自适应自旋CLH锁减少内存争用的自然趋势减少了进一步分散争用位置的动机,但可能需要未来的改进。
*/
private static final long serialVersionUID = -6001602636862214147L;
/**
* Number of processors, for spin control
* 处理器数量,为了自旋控制
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* CPU数量
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private static final int NCPU = Runtime.getRuntime().availableProcessors();
/**
* Maximum number of retries before enqueuing on acquisition
* 在为了获取而排队之前重试的最大数量
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 自旋数量
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 用于限制线程自旋的次数,共2^6(64)次。
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
/**
* Maximum number of retries before blocking at head on acquisition
* 在为了获取而在头部阻塞之前重试的最大数量
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 头自旋
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 用于限制线程在队列头部自旋的次数,共2^10(1024)次。
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
/**
* Maximum number of retries before re-blocking
* 在重阻塞前重试的最大数量
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 最大头自旋
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 用于限制线程自旋的最大次数,共2^16次。
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
/**
* The period for yielding when waiting for overflow spinlock
* 当为了溢出自旋锁而等待时让步的周期
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* 溢出让步率
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- TODO。
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
/**
* The number of bits to use for reader count before overflowing
* 在溢出之前为了读线程总数而使用的比特数量
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- TODO
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- TODO。
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private static final int LG_READERS = 7;
// Values for lock state and stamp operations
// 锁状态和邮戳操作的值
// ---- 读单位:1
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
private static final long RUNIT = 1L;
// ---- 写比特:128
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1000 0000
private static final long WBIT = 1L << LG_READERS;
// ---- 读比特:127
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1111
private static final long RBITS = WBIT - 1L;
// ---- 读满溢:126
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1110
private static final long RFULL = RBITS - 1L;
// ---- 全(读/写)比特:255
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1111:127
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1000 0000:128
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111:255
private static final long ABITS = RBITS | WBIT;
// note overlap with ABITS
// 与全比特重叠
// ---- 非比特:
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1111:127
// ---- 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1000 0000
private static final long SBITS = ~RBITS;
// Initial value for lock state; avoid failure value zero
// 初始化锁状态的值,避免失败值为0
// ---- 原始:256
// ---- 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 0000:256
private static final long ORIGIN = WBIT << 1;
// Special value from cancelled acquire methods so caller can throw IE
// 来自于已取消获取方法的指定值,所以调用者可以抛出异常
private static final long INTERRUPTED = 1L;
// Values for node status; order matters
// 节点状态值;排序标志
private static final int WAITING = -1;
private static final int CANCELLED = 1;
// Modes for nodes (int not boolean to allow arithmetic)
// 节点的模式(int类型而非布尔类型以允许演算)
private static final int RMODE = 0;
private static final int WMODE = 1;
/**
* Wait nodes
* 等待节点
*/
static final class WNode {
// ----前驱节点
volatile WNode prev;
// ---- 后继节点
volatile WNode next;
// list of linked readers
// 链接读线程的列表
volatile WNode cowait;
// non-null while possibly parked
// 在可以唤醒期间不为null
volatile Thread thread;
// 0, WAITING, or CANCELLED
// 0,-1或1
volatile int status;
// RMODE or WMODE
// 读模式或写模式
final int mode;
WNode(int m, WNode p) {
// ---- 模式和前驱节点是必须有的。
mode = m;
prev = p;
}
}
/**
* Head of CLH queue
* 同步队列的头
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 头
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 持有同步队列的头节点
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private transient volatile WNode whead;
/**
* Tail (last) of CLH queue
* 同步队列的尾节点
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 尾节点
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 持有同步队列的尾节点
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private transient volatile WNode wtail;
// views
// 视图
// 读锁视图
transient ReadLockView readLockView;
// 写锁视图
transient WriteLockView writeLockView;
// 读写锁视图
transient ReadWriteLockView readWriteLockView;
/**
* Lock sequence/state
* 锁序号/状态
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 状态
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 记录锁的状态/序号
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private transient volatile long state;
/**
* extra reader count when state read count saturated
* 当状态读取总数满溢时额外读线程总数
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 读线程溢出
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 用于在读线程数量溢出时记录溢出的读线程总数
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
private transient int readerOverflow;
/**
* Creates a new lock, initially in unlocked state.
* 创建一个新锁,初始化为未加锁状态。
*
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 邮戳锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* @Description: --------------------------------------------------------- 逻辑 ---------------------------------------------------------
*/
public StampedLock() {
// ---- [状态]的初始值为1 << 8,即256
state = ORIGIN;
}
/**
* Exclusively acquires the lock, blocking if necessary until available.
* 排它获取锁,如果必要则阻塞至可用
*
* @return a stamp that can be used to unlock or convert mode 可用于解锁或转换模式的邮戳
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 写锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 获取当前邮戳锁的写锁
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long writeLock() {
// bypass acquireWrite in fully unlocked case only
// 只在完全解锁的情况下绕过获取写
long s, next;
// ---- 方法首先会将[状态]和[全比特]执行位与操作,并判断结果是否为0。如果结果为0,意味着当前邮戳锁并未
// 被持有写锁,因此可以产生一个代表写锁的邮戳。写锁的邮戳通过在[状态]原值的基础上增加[写比特]实现,为
// 了避免线程安全问题该操作通过CAS操作实现。
// ---- 如果位于操作的结果不为0,或者在演算写锁邮戳时失败,则意味着当前邮戳锁的写锁已被获取/持有,因此
// 直接通过acquireWrite方法返回当前的写锁。
return ((((s = state) & ABITS) == 0L && U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : acquireWrite(false, 0L));
}
/**
* Exclusively acquires the lock if it is immediately available.
* 如果立即可用则排它获取锁
*
* @return a stamp that can be used to unlock or convert mode, or zero if the lock is not available
* 一个可用于解锁/转换模式的邮戳,或者如果锁不可用则为0
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 尝试写锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 尝试获取当前邮戳锁的写锁,成功则获得邮戳,否则返回0。
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long tryWriteLock() {
// ---- 方法会判断[状态]与[全比特]的位于结果是否为0,是则意味着当前邮戳锁的写锁未被获取,可尝试通过CAS
// 操作将[状态]增加一个[写比特]。如果CAS操作执行成功则返回增加后的[状态]作为邮戳;而如果当前邮戳锁的写
// 锁已被持有或CAS增长[状态]失败,则返回0表示尝试加锁写锁失败。
long s, next;
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : 0L);
}
/**
* Exclusively acquires the lock if it is available within the given time and the current thread has not been
* interrupted. Behavior under timeout and interruption matches that specified for method
* {@link Lock#tryLock(long, TimeUnit)}.
* 如果锁在指定时间可用并且当前线程未被中断,独占获取锁。超时和中断下的行为与为
* tryLock(long, TimeUnit)方法指定的行为相匹配。
*
* @param time the maximum time to wait for the lock 为锁等待的最大时间
* @param unit the time unit of the {@code time} argument 时间参数的时间单位
* @return a stamp that can be used to unlock or convert mode, or zero if the lock is not available
* 一个可用于解锁/转换模式的邮戳,如果锁不可用则为0。
* @throws InterruptedException if the current thread is interrupted before acquiring the lock
* 中断异常:如果当前线程在获取锁之前中断
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 尝试写锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 尝试获取当前邮戳锁的写锁,如果当前邮戳锁支持获取则返回邮戳,否则有限等待至支持获取为止,超出指定
* 等待时间返回0。线程如果在进入/等待时中断会抛出中断异常,但中断状态会被清除。
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long tryWriteLock(long time, TimeUnit unit) throws InterruptedException {
// ---- 方法首先会计算出指定时间的超时时间,随后判断当前线程是否已被中断,是则直接抛出中断异常。
long nanos = unit.toNanos(time);
if (!Thread.interrupted()) {
// ---- 如果当前线程在进入方法时未被中断,则方法会尝试获取写锁邮戳,成功则直接返回;否则再判断等待
// 时间是否合法,不合法则直接返回0表示失败;而在指定等待时间合法的情况下,如果计算得到的死亡时间
// 线不合法,则强制指定为合法值1,随后以有限等待的方式获取邮戳。
long next, deadline;
if ((next = tryWriteLock()) != 0L)
return next;
if (nanos <= 0L)
return 0L;
// ---- 如果时间尚未超时,
if ((deadline = System.nanoTime() + nanos) == 0L)
deadline = 1L;
if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
return next;
}
throw new InterruptedException();
}
/**
* Exclusively acquires the lock, blocking if necessary until available or the current thread is interrupted. Behavior
* under interruption matches that specified for method {@link Lock#lockInterruptibly()}.
* 独占获取锁,如果必要则阻塞,直至锁锁可用或当前线程被中断。中断下的情况与writeLockInterruptibly()方法匹配。
*
* @return a stamp that can be used to unlock or convert mode 一个可用于解锁或转换模式的时间戳。
* @throws InterruptedException if the current thread is interrupted before acquiring the lock
* 中断异常:如果当前线程在获取锁之间被中断
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 写锁(可中断)
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 获取当前邮戳锁的写锁,如果当前邮戳锁支持获取则返回邮戳,否则无限等待至支持获取为止。线程如果在进
* 入/等待时中断会抛出中断异常,但中断状态会被清除。
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long writeLockInterruptibly() throws InterruptedException {
// ---- 方法首先会判断当前线程是否已被中断,是则抛出中断异常;否则以无限等待的方式获取邮戳,直至成功获
// 取并返回或因为中断而抛出中断异常为止。
long next;
if (!Thread.interrupted() &&
(next = acquireWrite(true, 0L)) != INTERRUPTED)
return next;
throw new InterruptedException();
}
/**
* Non-exclusively acquires the lock, blocking if necessary until available.
* 非独占获取锁,如果必要则阻塞至锁可用。
*
* @return a stamp that can be used to unlock or convert mode
* 返回一个可用于解锁/转换模式的邮戳。
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 读锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 获取当前邮戳锁的写锁,如果当前邮戳锁支持获取则返回邮戳,否则无限等待至支持获取为止。线程如果在进
* 入/等待时中断会抛出中断异常,但中断状态会被清除。
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long readLock() {
// bypass acquireRead on common uncontended case
// 在常规无竞争的情况下避开acquireRead()方法
// ---- 方法首先会判断[头/尾节点]是否相同,相同意味着当前同步队列中不存在等待获取锁的线程,也就意味着当
// 前线程直接参与读锁的获取不会导致同步队列中的线程长时间/永远无法获取写锁,因此当前线程便具备了直接
// 尝试获取锁的权利。
// ---- 当同步队列中没有等待线程时,方法会判断[状态]与[全比特]的位与结果是否小于[读满溢],该位与结果的本质
// 是当前邮戳锁的读锁持有总数。当读锁持有总数小于[读满溢]时则意味着当前线程可以直接通过CAS将[状态]递增一
// 个[读单位]的方式获取新读锁邮戳,因为当读锁持有总数 >= [读满溢]时,读锁持有总数就需要[读线程溢出]来额外
// 记录了。
// ---- 上述流程是基于无竞争理想环境下的快速行为,如果条件不满足,或者快速获取读锁邮戳失败,则就需要调
// 用acquireRead(boolean interruptible, long deadline)方法来进入完整流程,该流程中包含了线程等待/唤醒/清理
// 等其它逻辑。
long s = state, next;
return ((whead == wtail && (s & ABITS) < RFULL && U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
next :
acquireRead(false, 0L));
}
/**
* Non-exclusively acquires the lock if it is immediately available.
* 如果立即可用则非独占获取锁。
*
* @return a stamp that can be used to unlock or convert mode, or zero if the lock is not available
* 一个可用于解锁/转换状态的邮戳,或如果锁不可用则为0。
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 尝试读锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 尝试获取当前邮戳锁的读锁,如果当前邮戳锁的写锁未被持有则返回邮戳;否则返回0表示持有读锁失败。
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long tryReadLock() {
for (; ; ) {
long s, m, next;
if ((m = (s = state) & ABITS) == WBIT)
// ---- 在循环中,方法首先会判断[状态]与[全比特]的位与结果是否为[写比特],是则说明当前邮戳锁的写
// 锁已被获取,因此当前线程不具备获取读锁的可能,因此直接返回0表示获取读锁失败。与其它形式的读
// 锁不同,"特殊值"形式的读锁方法不会判断同步队列中是否有等待中的线程,因此该形式的方法总是致力
// 于令当前线程优先获取读/写锁。
return 0L;
else if (m < RFULL) {
// ---- 如果位与结果小于[读满溢],说明读锁持有总数在当前周期中尚未溢出,因此可以直接通过CAS操作将
// [状态]增加[读单位]获取读锁邮戳。CAS操作成功则直接返回,否则便进入下个循环。
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
} else if ((next = tryIncReaderOverflow(s)) != 0L)
// ---- 如果位与结果大于等于[读满溢],意味着读锁持有总数在当前周期中已经满溢,需要开启新的周期进行
// 记录,这一步通过tryIncReaderOverflow(long state)方法实现。当然,这未必是一定成功的,因此失败的
// 情况下旧需要重入循环。
return next;
}
}
/**
* Non-exclusively acquires the lock if it is available within the given time and the current thread has not been
* interrupted. Behavior under timeout and interruption matches that specified for method
* {@link Lock#tryLock(long, TimeUnit)}.
* 如果邮戳锁在指定时间内可用并且线程没有被中断则非独占获取读锁。在超时&中断的情况下该方法的行为与
* tryLock(long, TimeUnit)方法匹配。
* 中断下的情况与writeLockInterruptibly()方法匹配。
*
* @param time the maximum time to wait for the lock 等待锁的最大时间
* @param unit the time unit of the {@code time} argument 时间参数的时间单位
* @return a stamp that can be used to unlock or convert mode, or zero if the lock is not available
* 一个可用于解锁,或转换模式的邮戳,如果锁不可用则为0.
* @throws InterruptedException if the current thread is interrupted before acquiring the lock
* 中断异常:如果当前线程在获取锁之前被中断
* @Description: --------------------------------------------------------- 名称 ---------------------------------------------------------
* ---- 尝试读锁
* @Description: --------------------------------------------------------- 作用 ---------------------------------------------------------
* ---- 获取当前邮戳锁的写锁,如果当前邮戳锁支持获取则返回邮戳,否则有限等待至支持获取为止,超时指定等待时
* 间则返回0。线程如果在进入/等待时中断会抛出中断异常,但中断状态会被清除。
* @Description: --------------------------------------------------------- 注意 ---------------------------------------------------------
*/
public long tryRe