AQS 类中的属性以及方法说明
AQS 类中的属性以及方法说明
AbstractQueuedSynchronizer 类的描述信息
提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量、事件等)。此类被设计为大多数类型的同步器的有用基础,这些同步器依赖于单个原子 int 值来表示状态。子类必须定义更改此状态的受保护方法,并定义该状态在获取或释放此对象方面的含义。鉴于这些,本类中的其他方法执行所有排队和阻塞机制。子类可以维护其他状态字段,但仅跟踪使用方法 getState()、setState(int)和compareAndSetState(int,int) 操作的原子更新的 int 值。
子类应定义为非公共内部助手类,用于实现其封闭类的同步属性。AbstractQueuedSynchronizer类不实现任何同步接口。相反,它定义了 acquiredInterruptible() 等方法,具体锁和相关同步器可以根据需要调用这些方法来实现它们的公共方法。
此类支持默认的独占模式和共享方式中的一种或两种。 当以独占模式获取时,其他线程尝试的获取无法成功。由多个线程获取的共享模式可能(但无需)成功。除了在机械意义上,这个类不理解这些差异,当共享模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。 在不同模式下等待的线程共享相同的FIFO队列。 通常,实现子类只支持这些模式之一,但是两者都可以在ReadWriteLock中发挥作用 。通常,实现子类只支持其中一种模式,但两者都可以在 ReadWriteLock 中发挥作用。仅支持独占模式或共享模式的子类不需要定义支持未使用模式的方法。
该类定义了一个嵌套的 ConditionObject 类,该类可由支持独占模式的子类用作 Condition 实现,其中方法 isHeldExclusive() 报告是否以独占方式保持与当前线程的同步,方法release(int)与当前调用getState()值完全释放此目的,和acquire(int) ,给定此保存的状态值,最终将此对象恢复到其先前获取的状态。AbstractQueuedSynchronizer方法将创建此类条件,因此如果不能满足此约束,请勿使用该约束。 ConditionObject的行为当然取决于其同步器实现的语义。
此类提供内部队列的检查、检测和监视方法,以及条件对象的类似方法。这些可以根据需要使用 AbstractQueuedSynchronizer 作为其同步机制导出到类中。
此类的序列化仅存储底层原子整数维护状态,因此反序列化对象具有空线程队列。需要可序列化的典型子类将定义一个 readObject 方法,该方法在反序列化时将其还原为已知的初始状态。
示例用法:
使用这个类用作同步的基础上,重新定义以下方法,如适用,通过检查和/或修改使用所述同步状态getState() , setState(int)和/或compareAndSetState(int, int) :
- tryAcquire(int)
- tryRelease(int)
- tryAcquireShared(int)
- tryReleaseShared(int)
- isHeldExclusively()
每个这些方法默认抛出UnsupportedOperationException 。 这些方法的实现必须是线程安全的,通常应该是短的而不是阻止的。 定义这些方法是唯一支持使用此类的方法。 所有其他方法都被声明为final ,因为它们不能独立变化。
您还可以找到来自继承的方法AbstractOwnableSynchronizer有用跟踪线程拥有独家同步的。 我们鼓励您使用它们 - 这样可以使监控和诊断工具帮助用户确定哪些线程持有锁定。
即使该类基于内部FIFO队列,它也不会自动强制执行FIFO获取策略。独占同步的核心形式如下:
Acquire:
while (!tryAcquire(arg)) {
<em>enqueue thread if it is not already queued</em>;
<em>possibly block current thread</em>;
}
Release:
if (tryRelease(arg))
<em>unblock the first queued thread</em>;
(共享模式类似,但可能涉及级联信号。)
因为在采集检查入队之前调用,所以新获取的线程可能闯入其他被阻塞和排队的。 但是,如果需要,您可以通过内部调用一个或多个检查方法来定义tryAcquire和/或tryAcquireShared来禁用驳船,从而提供一个合理的 FIFO采购订单。 特别地,最公平同步器可以定义tryAcquire返回false如果hasQueuedPredecessors() (具体地设计成由公平同步器中使用的方法)返回true 。 其他变化是可能的。
吞吐量和可扩展性通常对于默认的驳船(也称为贪心 , 放弃和车队避免 )战略来说是最高的。 虽然这不能保证是公平的或无饥饿的,但较早排队的线程在稍后排队的线程之前被允许重新侦听,并且每次重新提供对于传入线程成功的机会。 此外,虽然获取在通常意义上不“旋转”,但是在阻止之前它们可以执行多个tryAcquire tryAcquire与其他计算的交互。 当独占同步只是简单地持有时,这样可以提供旋转的大部分好处,而没有大部分负债。 如果需要,您可以通过以前通过“快速路径”检查获取方法的调用进行扩充,可能预先检查hasContended()和/或hasQueuedThreads() ,以便只有在同步器可能不被竞争的情况下才能进行。
该类为同步提供了一个高效和可扩展的基础,部分原因是可以依靠int状态,获取和释放参数以及内部FIFO等待队列的同步器的使用范围。 当这不足够时,您可以使用atomic类,您自己的自定义Queue类和LockSupport类阻止支持从较低级别构建同步器。
用法示例:
这是一个不可重入互斥锁类,它使用零值来表示解锁状态,一个表示锁定状态。 虽然不可重入锁不严格要求记录当前的所有者线程,但是这样做无论如何使得使用更容易监视。 它还支持条件并公开其中一种仪器方法:
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Reports whether in locked state
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provides a Condition
Condition newCondition() { return new ConditionObject(); }
// Deserializes properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isHeldExclusively(); }
public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}
这是一个类似CountDownLatch的闩锁类,只是它只需要一个signal才能触发。 因为锁存器是非排他的,它使用shared获取和释放方法。
class BooleanLatch {
private static class Sync extends AbstractQueuedSynchronizer {
boolean isSignalled() { return getState() != 0; }
protected int tryAcquireShared(int ignore) {
return isSignalled() ? 1 : -1;
}
protected boolean tryReleaseShared(int ignore) {
setState(1);
return true;
}
}
private final Sync sync = new Sync();
public boolean isSignalled() { return sync.isSignalled(); }
public void signal() { sync.releaseShared(1); }
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
}
AbstractQueuedSynchronizer 属性以及方法
相关属性
/**
* 等待队列头部 (该节点不存储线程,只做指向功能,指向队列中虚拟节点(虚拟节点指向第一个等待节点))
*/
private transient volatile Node head;
/**
* 等待队列尾部(该节点不存储线程,只做指向功能,指向队列中最后一个等待节点)
*/
private transient volatile Node tail;
/**
* 同步状态(用不同的值,来表示锁是否被持有等等,例如:0 表示该锁未被占用 1表示该锁被占用 2 表示锁重入)
*/
private volatile int state;
/**
* 默认自旋的超时时间 (当等待的时间超过该值,则 park 该线程,当等待的时间小于该值,通过自旋尝试获取锁)
*/
static final long spinForTimeoutThreshold = 1000L;
相关方法 --- 排队实用程序
//========================== 排队实用程序 ==========================
/**
* 将节点插入队列,必要时进行初始化 (返回该节点的前置节点)
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
/**
* 根据给定的模式,为当前线程创建排队节点
*
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
/**
* 将队列头设置为节点,从而使其退出队列(设置该节点为虚拟节点)
*
* head ---> node(虚节点,thread=null,pre = null ) ---> 等待节点Node1 ---> 等待节点Node2 ---> tail
*/
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}
/**
* 唤醒节点的后继节点(如果存在)。
*/
private void unparkSuccessor(Node node) {
/*
* 如果状态为负(即,可能需要信号),尝试在信号发出之前清除。
* 如果失败或等待线程更改了状态,则可以。
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* 要唤醒(unpark)的线程保存在后继节点中,通常只是下一个节点。
* 但如果被取消或明显为空,则从 tail 向后遍历以找到实际的非取消后继对象。
*/
// 当前节点的后继节点(需要唤醒的节点)
Node s = node.next;
// 当 要唤醒的节点为空 或 要唤醒的节点已取消
// 则置空当前要唤醒的线程,从 tail 向后遍历找到实际的非取消的节点(最后一个非取消的节点),赋值给要唤醒的节点
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 唤醒后继节点
if (s != null)
LockSupport.unpark(s.thread);
}
/**
* 释放共享模式的动作 —— 发出后续信号并确保传播。
* (注意:对于独占模式,如果需要信号,release相当于调用 head 的 unparkSuccessor。)
*/
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
/**
* 设置头节点并传播行为 (共享模式下使用)
* 设置队列头,并检查后续程序是否可能在共享模式下等待,如果是,则在设置了 propagate>0 或 PROPAGATE 状态时进行传播。
*/
private void setHeadAndPropagate(Node node, int propagate) {
// 记录旧头部,以便在下面进行检查
Node h = head; // Record old head for check below
// 设置队列头,当前节点出队
setHead(node);
/*
* 当 propagate > 0
* 或 旧的 head 为空 (标识当前队列为空)
* 或 旧的 head.waitStatus < 0 (SIGNAL,CONDITION,PROPAGATE 状态)
* 或 新的 head 为空
* 或 新的 head.waitStatus < 0 (SIGNAL,CONDITION,PROPAGATE 状态)
*
* 判断当前节点的后继节点:为空 或 是共享节点
*
* 执行释放
*
*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
相关方法 --- 用于不同版本的 acquire 的实用程序
//========================== 用于不同版本的 acquire 的实用程序 ==========================
/**
* 取消正在尝试获取锁的节点(一般用于线程被打断,需要立即返回的情况)
*/
private void cancelAcquire(Node node) {
// 如果节点不存在,则忽略
if (node == null)
return;
node.thread = null;
/**
* 跳过已取消节点的前置任务
*/
Node pred = node.prev;
// pred.waitStatus > 0 表示前置节点也被取消了 (剔除前面 所有取消的节点)
// 目的:找到 node 前面第一个未取消的节点
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 当前取消节点的前置节点的后继节点(不一定是当前节点)
Node predNext = pred.next;
// 当前节点 node 设置为: 取消状态
node.waitStatus = Node.CANCELLED;
// 如果当前节点为 tail (说明为尾节点),将当前节点的剔除掉
if (node == tail && compareAndSetTail(node, pred)) {
//设置前置节点的next 为 null (因为现在它为 tail 尾节点)
compareAndSetNext(pred, predNext, null);
} else {
// 如果当前节点不是尾节点
int ws;
// 当 前置节点不是 head
// 并且 前置节点的waitStatus状态是 SIGNAL 或者 (前置节点的waitStatus状态不是取消状态 并且 设置前置状态为 SIGNAL 成功)
// 并且 前置节点的 thread 不为空
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
// 将当前节点的next 设置为前置节点next (主要是跳过当前节点)
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
// 唤醒后继节点
unparkSuccessor(node);
}
//将当前节点的next设置为自己(闭环),便于垃圾回收
node.next = node; // help GC
}
}
/**
* 检查并更新未能获取的节点的状态。如果线程应阻塞,则返回true。这是所有采集回路中的主要信号控制。需要pred==node.prev。
* 维护节点状态
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* 当前节点的前驱节点状态是 Single (Single 代表,释放锁时,唤醒后继节点),
* 则后续执行(parkAndCheckInterrupt)挂起等待
*/
return true;
if (ws > 0) {
/*
* ws > 0 代表前置节点已取消,剔除该前置节点
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus必须为0或PROPAGATE , 表示我们需要信号,但还没有 park。
* 调用者将需要重试,以确保它不能获取之前 park。
*
* 设置前驱节点的 waitStatus = SIGNAL (Single 代表,释放锁时,唤醒后继节点)
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
/**
* 中断当前线程
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
/**
* 唤醒当前线程,并返回中断状态
*/
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
/**
* 不同的获取方式,不同的独占/共享和控制模式。每一个都大致相同,但令人讨厌的是不同。
* 由于异常机制(包括确保我们在tryAcquire抛出异常时取消)和其他控制的相互作用,
* 只有一点点因子分解是可能的,至少不会对性能造成太大影响。
*/
/**
* 以独占不可中断模式获取队列中已存在的线程。用于条件等待方法和acquire方法。
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取前置节点是否为 head ;
// 是:尝试获取锁
// 否:向下执行,继续阻塞(park)
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
// 该节点获取锁成功
// 该节点出队
setHead(node);
// 将之前的虚节点 next 置为空,方便垃圾回收
p.next = null; // help GC
failed = false;
// 返回中断状态
return interrupted;
}
// 保证前置节点的状态是 SIGNAL ,保证前置节点释放之后,唤醒后续节点;
// 阻塞当前线程(等待唤醒后继续执行)
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
//当线程被中断,则返回中断状态
interrupted = true;
}
} finally {
//当线程获取锁成功后,执行失败,则取消该节点
if (failed)
cancelAcquire(node);
}
}
/**
* 以独占可中断模式获取(可响应中断)。
*/
private void doAcquireInterruptibly(int arg) throws InterruptedException {
// 将当前节点加入等待队列
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
// 获取前置节点是否为 head ;
// 是:尝试获取锁
// 否:向下执行,继续阻塞(park)
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
// 该节点获取锁成功
// 该节点出队
setHead(node);
// 将之前的虚节点 next 置为空,方便垃圾回收
p.next = null; // help GC
failed = false;
return;
}
// 保证前置节点的状态是 SIGNAL ,保证前置节点释放之后,唤醒后续节点;
// 阻塞当前线程(等待唤醒后继续执行)
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
//当线程被中断,则抛出异常
throw new InterruptedException();
}
} finally {
//当线程获取锁成功后,执行失败,则取消该节点
if (failed)
cancelAcquire(node);
}
}
/**
* 以独占计时模式获取。
*/
private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
// 判断最大等待时间是否合规
if (nanosTimeout <= 0L)
return false;
// 计算出 截止时间
final long deadline = System.nanoTime() + nanosTimeout;
// 加入等待队列
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
// 获取前置节点是否为 head ;
// 是:尝试获取锁
// 否:向下执行,继续阻塞(park)
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
// 该节点获取锁成功
// 该节点出队
setHead(node);
// 将之前的虚节点 next 置为空,方便垃圾回收
p.next = null; // help GC
failed = false;
return true;
}
//计算距离截止时间还有多少时间
nanosTimeout = deadline - System.nanoTime();
// 判断等待时间是否用完,用完则返回 false(因为这一步的时候,还没有获取锁)
if (nanosTimeout <= 0L)
return false;
// 1.保证前置节点的状态是 SIGNAL ,保证前置节点释放之后,唤醒后续节点;
// 2.判断剩余的时间小于系统定义的自旋时间,
// 小于:线程执行自旋方式获取锁(for循环)
// 否则:阻塞当前线程(阻塞 nanosTimeout 时间,时间到了,自动唤醒)
if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
//响应线程的中断
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
//当线程获取锁成功后,执行失败,则取消该节点
if (failed)
cancelAcquire(node);
}
}
/**
* 在共享不中断模式下获取。【忽略中断】
*
* 1.为当前线程创建排队节点,加入等待队列
* 2.for循环开始:判断当前节点的前置节点是否为 head?
* 是: 尝试获取锁
* 获取成功,节点出队,
* 获取失败,执行步骤 3
* 否:执行步骤 3
* 3.判断当前节点的前置节点 waitStatus == Node.SIGNAL
* 如果不是,设置为 Node.SIGNAL ,执行步骤 2
* 如果是, 阻塞(park)当前节点的线程,等待唤醒;节点被唤醒之后,执行步骤 2
*
*/
private void doAcquireShared(int arg) {
// 加入到等待队列中
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false; //线程的中断标识
for (;;) {
// 判断当前节点的前置节点是否是 head
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
// 设置 head 并向下传播(唤醒线程)
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
* 在共享可中断模式下获取。
*/
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
/**
* 以共享定时模式获取。
*/
private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
//截止时间
final long deadline = System.nanoTime() + nanosTimeout;
// 加入队列
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return true;
}
}
//距离截止时间还有多少时间
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L) //时间用完,直接返回 false
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
// 如果剩余的时间小于系统定义的自旋时间,才会执行自旋(for循环);
// 否则:阻塞当前 nanosTimeout ,时间到了,自动唤醒;
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
相关方法 --- 主要暴露的方法
//========================== 主要暴露的方法 ==========================
/**
* 尝试以独占模式获取。该方法应该查询对象的状态是否允许以独占模式获取,如果允许则获取它。
*
* 该方法总是由执行 acquire的线程调用。如果此方法报告失败,acquire方法可能会对线程进行排队(如果它还没有排队),直到从其他线程释放信号。
*
* 如果获取成功,则返回true
*/
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
/**
* 试图设置状态以反映独占模式下的释放。(此方法总是由执行释放的线程调用。)
*/
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
/**
* 尝试以共享模式获取。该方法应该查询对象的状态是否允许以共享模式获取,如果允许,则获取它。
* 返回值 < 0 :失败
* 返回值 = 0 :获取成功,但后续的共享模式获取无法成功
* 返回值 > 0 :获取成功,并且后续的共享模式的获取也可能成功
*
*/
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
/**
* 试图设置状态以反映共享模式下的释放。
*/
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
/**
* 如果同步仅与当前(调用)线程保持,则返回 true,否则返回 false
*/
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
/**
* 以独占模式获取,忽略中断.(如果被中断,线程执行完成之后,acquireQueued 方法返回中断标识)
*
* 实现方式是至少调用一次 tryAcquire(),成功返回。否则线程会排队,可能会反复阻塞和解阻塞,调用 tryAcquire() 直到成功
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//响应线程的中断
selfInterrupt();
}
/**
* 以独占模式可中断的获取。 如果中断则终止(如果获取过程中被中断,则会抛出 InterruptedException 异常)
*
* 首先检查中断状态,然后至少调用一次 tryAcquire(),成功后返回。
* 否则,线程会排队,可能会反复阻塞和解阻塞,调用 tryAcquire(),直到成功或线程中断
*/
public final void acquireInterruptibly(int arg) throws InterruptedException {
//判断是否中断,中断则抛出异常
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
// 如果唤醒的线程被中断,则响应中断 抛出异常,并取消该节点
doAcquireInterruptibly(arg);
}
/**
* 以独占模式可中断的获取,如果中断将中止,如果超时将获取失败。(如果被中断则终止,抛出 InterruptedException 异常)。
*
* 首先检查中断状态,然后至少调用一次 tryAcquire(),成功后返回。
* 否则,线程会排队,可能会反复阻塞和解阻塞,调用 tryAcquire(),直到成功,或者线程被中断,或者超时过去。
*/
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
// 线程是否被中断,中断则抛出异常
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquire
// 获取锁成功:直接返回 true
// 获取锁失败:在指定时间内以独占模式获取锁。并返回获取锁的情况
return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout);
}
/**
* 以独占模式释放锁。
*/
public final boolean release(int arg) {
// 调用子类实现,释放锁
if (tryRelease(arg)) {
// 唤醒后继节点
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
/**
* 以共享模式获取。忽略中断(如果被中断,线程执行完成之后,doAcquireShared 方法返回中断标识)
*
* 首先至少调用一次 tryAcquireShared(),成功后返回。否则线程会排队,可能会反复阻塞和解阻塞,调用 tryAcquireShared()直到成功。
*/
public final void acquireShared(int arg) {
/**
* 返回值 < 0 :失败
* 返回值 = 0 :获取成功,但后续的共享模式获取无法成功
* 返回值 > 0 :获取成功,并且后续的共享模式的获取也可能成功
*/
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
/**
* 以共享模式可中断的获取,如果中断将中止。(如果获取过程中被中断,则会抛出 InterruptedException 异常)
*
* 首先检查中断状态,然后至少调用一次 tryAcquireShared(),成功后返回。
* 否则,线程会排队,可能会反复阻塞和解阻塞,调用 tryacquishared(),直到成功或线程中断。
*/
public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
/**
* 在共享模式下尝试获取,如果中断将中止,如果超时将获取失败。(如果被中断则终止,抛出 InterruptedException 异常)。
*
* 首先检查中断状态,然后至少调用一次 tryAcquireShared(),成功后返回。
* 否则,线程会排队,可能会反复阻塞和解阻塞,调用 tryAcquireShared(),直到成功,或者线程被中断,或者超时过去。
*/
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquireShared(arg) >= 0 ||
doAcquireSharedNanos(arg, nanosTimeout);
}
/**
* 以共享模式释放。
*
* 通过在 tryReleaseShared() 返回true时解除一个或多个线程的阻塞来实现。
*/
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { //判断释放是否成功
doReleaseShared();
return true;
}
return false;
}
相关方法 --- 队列检查方法
//========================== 队列检查方法 ==========================
/**
* 查询是否有线程正在等待获取。
* 注意,由于中断和超时导致的取消可能随时发生,因此返回 true 并不保证任何其他线程都会获取。
*/
public final boolean hasQueuedThreads() {
return head != tail;
}
/**
* 查询是否有线程争用过这个同步器;也就是说,如果一个获取方法曾经被阻止。
*/
public final boolean hasContended() {
return head != null;
}
/**
* 返回队列中第一个(等待时间最长的)线程,如果当前没有线程排队,则返回 null。
*/
public final Thread getFirstQueuedThread() {
// handle only fast path, else relay
return (head == tail) ? null : fullGetFirstQueuedThread();
}
/**
* Version of getFirstQueuedThread called when fastpath fails
*/
private Thread fullGetFirstQueuedThread() {
Node h, s;
Thread st;
if (((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null) ||
((h = head) != null && (s = h.next) != null &&
s.prev == head && (st = s.thread) != null))
return st;
Node t = tail;
Thread firstThread = null;
while (t != null && t != head) {
Thread tt = t.thread;
if (tt != null)
firstThread = tt;
t = t.prev;
}
return firstThread;
}
/**
* 如果给定线程当前已排队,则返回true。
*/
public final boolean isQueued(Thread thread) {
if (thread == null)
throw new NullPointerException();
for (Node p = tail; p != null; p = p.prev)
if (p.thread == thread)
return true;
return false;
}
/**
* 如果明显的第一个排队线程(如果存在)正在以独占模式等待,则返回 true。
* 如果此方法返回 true,并且当前线程正在尝试以共享模式获取(即,这个方法是从从 tryAcquireShared 调用的),
* 那么可以保证当前线程不是第一个排队线程。仅在 ReentrantReadWriteLock中用作启发式。
*/
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
/**
* 查询是否有线程等待获取的时间比当前线程长。
*/
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
相关方法 --- 仪器仪表和监测方法
//========================== 仪器仪表和监测方法 ==========================
/**
* 返回等待获取的线程数的估计值。该值只是一个估计值,因为当该方法遍历内部数据结构时,线程数可能会动态变化。
* 该方法设计用于监控系统状态,而非同步控制。
*/
public final int getQueueLength() {
int n = 0;
for (Node p = tail; p != null; p = p.prev) {
if (p.thread != null)
++n;
}
return n;
}
/**
* 返回包含可能正在等待获取的线程的集合。由于在构造此结果时,实际的线程集可能会动态变化,因此返回的集合只是一个尽力而为的估计。
* 返回集合的元素没有特定的顺序。此方法旨在帮助构建提供更广泛监控设施的子类。
*/
public final Collection<Thread> getQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
return list;
}
/**
* 返回包含可能正在等待以独占模式获取的线程的集合。
* 这个方法与 getQueuedThreads() 具有相同的属性,不同之处在于它只返回那些由于独占获取而等待的线程。
*/
public final Collection<Thread> getExclusiveQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (!p.isShared()) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
}
return list;
}
/**
* 返回一个集合,其中包含可能等待以共享模式获取的线程。
* 这个方法与 getQueuedThreads() 具有相同的属性,不同之处在于它只返回那些因为共享获取而等待的线程。
*/
public final Collection<Thread> getSharedQueuedThreads() {
ArrayList<Thread> list = new ArrayList<Thread>();
for (Node p = tail; p != null; p = p.prev) {
if (p.isShared()) {
Thread t = p.thread;
if (t != null)
list.add(t);
}
}
return list;
}
/**
* 返回标识此同步器及其状态的字符串.后跟 getState() 的当前值,以及队列是否空。
*/
public String toString() {
int s = getState();
String q = hasQueuedThreads() ? "non" : "";
return super.toString() +
"[State = " + s + ", " + q + "empty queue]";
}
相关方法 --- 条件的内部支持方法
//========================== 条件的内部支持方法 ==========================
/**
* 如果节点(总是最初放置在条件队列中的节点)现在正在同步队列上等待重新获取,则返回true。
*/
final boolean isOnSyncQueue(Node node) {
// 当前节点处于条件等待状态
// 或 当前节点的前置节点为空
// 返回false,当前节点不在同步等待队列中,而是在 条件等待队列中
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// If has successor, it must be on queue
// 前提条件:节点不是条件等待节点、节点的前置节点非空
// 判断:如果节点有后继节点,则一定在队列中(一定不在条件等待队列)
if (node.next != null)
return true;
/**
*
* 前置条件: 节点不是条件等待节点、节点的前置节点非空、节点的后置节点为空
*
* node.prev 不为空 并且 不在同步队列中,因为将其放入队列的CAS可能会失败(enq()的时候)。
* 所以我们必须从尾部开始遍历以确保它确实成功了。
*
* 在对这个方法的调用中,它总是在尾部附近,除非CAS失败(这是不太可能的),否则它会在那里,所以我们几乎不会遍历太多。
*
*/
return findNodeFromTail(node);
}
/**
* 通过从尾部向后搜索,如果节点位于同步队列中,则返回true。仅在 isOnSyncQueue需要时调用。
*/
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
/**
* 将节点从条件队列转移到同步队列。如果成功返回true。
*/
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
* 将节点的状态值 由 CONDITION 改为 0
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
//将该节点添加到 同步队列中去
Node p = enq(node);
int ws = p.waitStatus;
// ws > 0 如果该节点已取消 , 则从 await 方法中唤醒
// ws <= 0 ,尝试修改状态为 SIGNAL, 则从 await 方法中唤醒
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
/**
* 必要时,在取消等待后将节点转移到同步队列。如果线程在发出信号之前被取消,则返回true
*/
final boolean transferAfterCancelledWait(Node node) {
// 设置节点状态 从条件等待状态,设置为普通状态
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
enq(node);
return true;
}
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
/**
* 使用当前状态值调用 release; 返回保存的状态。 取消node并在失败时抛出异常。
*/
final int fullyRelease(Node node) {
boolean failed = true;
try {
// 注意:是完全释放锁(传的值是 savedState )
int savedState = getState();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
相关方法 --- 条件仪表方法
//========================== 条件仪表方法 ==========================
/**
* 查询给定的ConditionObject是否使用此同步器作为其锁。
*/
public final boolean owns(ConditionObject condition) {
return condition.isOwnedBy(this);
}
/**
* 查询是否有任何线程正在等待与此同步器关联的给定条件。
* 注意,由于超时和中断可能随时发生,因此 true返回不能保证将来的信号将唤醒任何线程。
* 该方法主要用于监测系统状态。
*/
public final boolean hasWaiters(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.hasWaiters();
}
/**
* 返回与此同步器关联的给定条件下等待的线程数的估计值。
* 请注意,由于超时和中断可能随时发生,因此估计值仅作为实际服务员数量的上限。
* 方法设计用于监控系统状态,而不是用于同步控制。
*/
public final int getWaitQueueLength(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitQueueLength();
}
/**
* 返回一个集合,其中包含可能正在等待与此同步器关联的给定条件的线程。
* 由于在构造此结果时,实际的线程集可能会动态变化,因此返回的集合只是一个尽力而为的估计。
* 返回集合的元素没有特定的顺序。
*/
public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitingThreads();
}