- 所有已实现的接口:
-
Serializable
int
值来表示状态的同步器的有用基础。子类必须定义改变这个状态的受保护方法,并定义这个状态在被获取或释放时的含义。有了这些,这个类中的其他方法执行所有排队和阻塞机制。子类可以维护其他状态字段,但只有使用方法getState()
、setState(int)
和compareAndSetState(int, int)
原子更新的int
值才会被跟踪以进行同步。
子类应该被定义为用于实现其封闭类的同步属性的非公共内部辅助类。类AbstractQueuedSynchronizer
不实现任何同步接口。相反,它定义了诸如acquireInterruptibly(int)
之类的方法,可以由具体的锁和相关同步器适当地调用以实现它们的公共方法。
这个类支持默认的独占模式和共享模式中的一个或两个。在独占模式下获取时,其他线程尝试获取将无法成功。多个线程以共享模式获取可能(但不一定)会成功。这个类不“理解”这些差异,除了在机械意义上,当共享模式获取成功时,下一个等待的线程(如果存在)也必须确定它是否也可以获取。在不同模式下等待的线程共享相同的FIFO队列。通常,实现子类只支持这些模式中的一个,但在例如ReadWriteLock
中,两者都可能发挥作用。只支持独占模式或只支持共享模式的子类不需要定义支持未使用模式的方法。
这个类定义了一个嵌套的AbstractQueuedSynchronizer.ConditionObject
类,可以被支持独占模式的子类用作Condition
实现,其中方法isHeldExclusively()
报告了同步是否完全由当前线程持有,使用当前getState()
值调用的方法release(int)
完全释放了这个对象,并且acquire(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int, boolean, boolean, boolean, long)
,给定这个保存的状态值,最终将这个对象恢复到其先前获取的状态。没有AbstractQueuedSynchronizer
方法会创建这样的条件,所以如果无法满足这个约束,请不要使用它。当然,AbstractQueuedSynchronizer.ConditionObject
的行为取决于其同步器实现的语义。
这个类为内部队列提供了检查、检测和监控方法,以及用于条件对象的类似方法。这些方法可以根据需要导出到使用AbstractQueuedSynchronizer
进行同步机制的类中。
这个类的序列化仅存储维护状态的基础原子整数,因此反序列化的对象具有空线程队列。通常需要可序列化的子类将定义一个readObject
方法,在反序列化时将其恢复到已知的初始状态。
用法
要将这个类用作同步器的基础,通过检查和/或修改同步状态使用getState()
、setState(int)
和/或compareAndSetState(int, int)
重新定义以下方法:
UnsupportedOperationException
。这些方法的实现必须在内部是线程安全的,并且通常应该是简短的且不会阻塞。定义这些方法是唯一支持使用这个类的方法。所有其他方法都声明为final
,因为它们不能独立变化。
您可能还会发现从AbstractOwnableSynchronizer
继承的方法对于跟踪拥有独占同步器的线程很有用。鼓励您使用它们--这样可以使监视和诊断工具帮助用户确定哪些线程持有锁。
尽管这个类基于内部FIFO队列,但它不会自动强制执行FIFO获取策略。独占同步的核心形式如下:
获取: while (!tryAcquire(arg)) { 如果尚未排队,则将线程排队; 可能阻塞当前线程; } 释放: if (tryRelease(arg)) 解除阻塞第一个排队的线程;(共享模式类似,但可能涉及级联信号。)
因为在获取时调用的检查在排队之前,新获取的线程可能会插队到其他被阻塞和排队的线程之前。但是,如果需要,您可以通过定义tryAcquire
和/或tryAcquireShared
来禁用插队,内部调用一个或多个检查方法,从而提供一个公平的FIFO获取顺序。特别是,大多数公平同步器可以定义tryAcquire
,如果hasQueuedPredecessors()
(专门设计用于公平同步器使用的方法)返回true
,则返回false
。其他变体也是可能的。
默认插队(也称为贪婪、放弃和避免车队)策略通常具有最高的吞吐量和可伸缩性。虽然不能保证是公平的或无饥饿的,但先前排队的线程被允许在后排队的线程之前重新竞争,并且每次重新竞争都有一个无偏见的机会成功对抗新到来的线程。此外,虽然获取不会以通常意义上的“自旋”方式进行,但它们可能在阻塞之前执行多次调用tryAcquire
,并与其他计算交替进行。当独占同步仅短暂持有时,这提供了自旋的大部分好处,而在不持有时则没有大部分的责任。如果需要,您可以通过在调用获取方法之前增加“快速路径”检查,可能预先检查hasContended()
和/或hasQueuedThreads()
,只有在同步器可能不会被争用时才这样做。
这个类通过将其使用范围专门化为可以依赖int
状态、获取和释放参数以及内部FIFO等待队列的同步器,提供了高效和可伸缩的同步基础。当这不够时,您可以使用atomic
类、自定义的Queue
类和LockSupport
阻塞支持从更低级别构建同步器。
用法示例
这是一个非重入互斥锁类的示例,它使用值零表示未锁定状态,使用值一表示已锁定状态。虽然非重入锁不严格要求记录当前所有者线程,但这个类仍然这样做是为了使使用更容易监视。它还支持条件并公开一些检测方法:
class Mutex implements Lock, java.io.Serializable {
// 我们的内部辅助类
private static class Sync extends AbstractQueuedSynchronizer {
// 如果状态为零,则获取锁
public boolean tryAcquire(int acquires) {
assert acquires == 1; // 否则未使用
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 通过将状态设置为零来释放锁
protected boolean tryRelease(int releases) {
assert releases == 1; // 否则未使用
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// 报告是否处于锁定状态
public boolean isLocked() {
return getState() != 0;
}
public boolean isHeldExclusively() {
// 一个数据竞争,但由于无中生有的保证是安全的
return getExclusiveOwnerThread() == Thread.currentThread();
}
// 提供一个Condition
public Condition newCondition() {
return new ConditionObject();
}
// 正确反序列化
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // 重置为未锁定状态
}
}
// sync对象完成所有繁重的工作。我们只需转发给它。
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.isLocked(); }
public boolean isHeldByCurrentThread() {
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
获取和释放方法。
类 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);
}
}
- 自JDK版本:
- 1.5
- 参见:
-
Nested Class Summary
-
Constructor Summary
ModifierConstructorDescriptionprotected
创建一个具有初始同步状态为零的新AbstractQueuedSynchronizer
实例。 -
Method Summary
Modifier and TypeMethodDescriptionfinal void
acquire
(int arg) 以独占模式获取,忽略中断。final void
acquireInterruptibly
(int arg) 以独占模式获取,如果被中断则中止。final void
acquireShared
(int arg) 以共享模式获取,忽略中断。final void
acquireSharedInterruptibly
(int arg) 以共享模式获取,如果被中断则中止。protected final boolean
compareAndSetState
(int expect, int update) 如果当前状态值等于期望值,则以原子方式将同步状态设置为给定的更新值。final Collection
<Thread> 返回一个包含可能正在等待以独占模式获取的线程的集合。final Thread
返回队列中的第一个(等待时间最长)线程,如果当前没有线程在队列中则返回null
。final Collection
<Thread> 返回一个包含可能正在等待获取的线程的集合。final int
返回等待获取的线程数的估计值。final Collection
<Thread> 返回一个包含可能正在等待以共享模式获取的线程的集合。protected final int
getState()
返回当前同步状态的当前值。final Collection
<Thread> 返回一个包含可能正在等待与此同步器关联的给定条件的线程的集合。final int
返回等待与此同步器关联的给定条件的线程数的估计值。final boolean
查询是否有任何线程曾经争夺过获取此同步器;也就是说,是否曾经有获取方法被阻塞过。final boolean
查询是否有任何线程等待获取的时间比当前线程长。final boolean
查询是否有任何线程正在等待获取。final boolean
查询是否有任何线程正在等待与此同步器关联的给定条件。protected boolean
如果同步是相对于当前(调用)线程独占的,则返回true
。final boolean
如果给定线程当前在队列中,则返回true
。final boolean
owns
(AbstractQueuedSynchronizer.ConditionObject condition) 查询给定的 ConditionObject 是否将此同步器用作其锁。final boolean
release
(int arg) 以独占模式释放。final boolean
releaseShared
(int arg) 以共享模式释放。protected final void
setState
(int newState) 设置同步状态的值。toString()
返回标识此同步器及其状态的字符串。protected boolean
tryAcquire
(int arg) 尝试以独占模式获取。final boolean
tryAcquireNanos
(int arg, long nanosTimeout) 尝试以独占模式获取,如果被中断则中止,并且如果给定的超时时间过去则失败。protected int
tryAcquireShared
(int arg) 尝试以共享模式获取。final boolean
tryAcquireSharedNanos
(int arg, long nanosTimeout) 尝试以共享模式获取,如果被中断则中止,并且如果给定的超时时间过去则失败。protected boolean
tryRelease
(int arg) 尝试设置状态以反映以独占模式释放。protected boolean
tryReleaseShared
(int arg) 尝试设置状态以反映以共享模式释放。Methods declared in class java.util.concurrent.locks.AbstractOwnableSynchronizer
getExclusiveOwnerThread, setExclusiveOwnerThread
-
Constructor Details
-
AbstractQueuedSynchronizer
protected AbstractQueuedSynchronizer()创建一个具有初始同步状态为零的新AbstractQueuedSynchronizer
实例。
-
-
Method Details
-
getState
protected final int getState()返回当前同步状态的当前值。此操作具有volatile
读取的内存语义。- 返回:
- 当前状态值
-
setState
protected final void setState(int newState) 设置同步状态的值。此操作具有volatile
写入的内存语义。- 参数:
-
newState
- 新状态值
-
compareAndSetState
protected final boolean compareAndSetState(int expect, int update) 如果当前状态值等于期望值,则以原子方式将同步状态设置为给定的更新值。此操作具有volatile
读取和写入的内存语义。- 参数:
-
expect
- 期望值 -
update
- 新值 - 返回:
-
如果成功则返回
true
。返回 false 表示实际值与期望值不相等。
-
tryAcquire
protected boolean tryAcquire(int arg) 尝试以独占模式获取。此方法应查询对象的状态是否允许以独占模式获取,并在允许时获取它。此方法始终由执行获取的线程调用。如果此方法报告失败,则获取方法可能会将线程排队,如果尚未排队,则直到被其他线程的释放信号唤醒。这可用于实现方法
Lock.tryLock()
。默认实现会抛出
UnsupportedOperationException
。- 参数:
-
arg
- 获取参数。此值始终是传递给获取方法的值,或者是在条件等待时保存的值。否则,该值未解释,可以表示任何您喜欢的内容。 - 返回:
-
如果成功则返回
true
。成功后,此对象已被获取。 - 抛出:
-
IllegalMonitorStateException
- 如果获取会使此同步器处于非法状态。为了使同步正常工作,必须以一致的方式抛出此异常。 -
UnsupportedOperationException
- 如果不支持独占模式
-
tryRelease
protected boolean tryRelease(int arg) 尝试设置状态以反映以独占模式释放。此方法始终由执行释放的线程调用。
默认实现会抛出
UnsupportedOperationException
。- 参数:
-
arg
- 释放参数。此值始终是传递给释放方法的值,或者在条件等待时的当前状态值。否则,该值未解释,可以表示任何您喜欢的内容。 - 返回:
-
如果此对象现在处于完全释放状态,则返回
true
,以便任何等待的线程可以尝试获取;否则返回false
。 - 抛出:
-
IllegalMonitorStateException
- 如果释放会使此同步器处于非法状态。为了使同步正常工作,必须以一致的方式抛出此异常。 -
UnsupportedOperationException
- 如果不支持独占模式
-
isHeldExclusively
protected boolean isHeldExclusively()返回true
如果相对于当前(调用)线程独占地持有同步。每次调用AbstractQueuedSynchronizer.ConditionObject
方法时会调用此方法。默认实现会抛出
UnsupportedOperationException
。此方法仅在AbstractQueuedSynchronizer.ConditionObject
方法内部调用,因此如果不使用条件,则无需定义此方法。- 返回:
-
如果独占地持有同步,则返回
true
;否则返回false
- 抛出:
-
UnsupportedOperationException
- 如果不支持条件
-
acquire
public final void acquire(int arg) 以独占模式获取,忽略中断。通过至少调用一次tryAcquire(int)
来实现,在成功时返回。否则,线程将排队,可能会重复阻塞和解除阻塞,调用tryAcquire(int)
直到成功。此方法可用于实现方法Lock.lock()
。- 参数:
-
arg
- 获取参数。此值传递给tryAcquire(int)
,但除此之外不被解释,可以表示任何内容。
-
acquireInterruptibly
以独占模式获取,如果被中断则中止。首先检查中断状态,然后通过至少调用一次tryAcquire(int)
来实现,在成功时返回。否则,线程将排队,可能会重复阻塞和解除阻塞,调用tryAcquire(int)
直到成功或线程被中断。此方法可用于实现方法Lock.lockInterruptibly()
。- 参数:
-
arg
- 获取参数。此值传递给tryAcquire(int)
,但除此之外不被解释,可以表示任何内容。 - 抛出:
-
InterruptedException
- 如果当前线程被中断
-
tryAcquireNanos
尝试以独占模式获取,如果被中断则中止,并且如果给定的超时时间过去则失败。首先检查中断状态,然后通过至少调用一次tryAcquire(int)
来实现,在成功时返回。否则,线程将排队,可能会重复阻塞和解除阻塞,调用tryAcquire(int)
直到成功或线程被中断或超时时间过去。此方法可用于实现方法Lock.tryLock(long, TimeUnit)
。- 参数:
-
arg
- 获取参数。此值传递给tryAcquire(int)
,但除此之外不被解释,可以表示任何内容。 -
nanosTimeout
- 等待的最大纳秒数 - 返回:
-
如果获取成功则返回
true
;如果超时则返回false
- 抛出:
-
InterruptedException
- 如果当前线程被中断
-
release
public final boolean release(int arg) 以独占模式释放。如果tryRelease(int)
返回true,则通过解除阻塞一个或多个线程来实现。此方法可用于实现方法Lock.unlock()
。- 参数:
-
arg
- 释放参数。此值传递给tryRelease(int)
,但除此之外不被解释,可以表示任何内容。 - 返回:
-
从
tryRelease(int)
返回的值
-
hasQueuedThreads
public final boolean hasQueuedThreads()查询是否有任何线程正在等待获取。请注意,由于中断和超时导致的取消可能随时发生,因此返回true
并不保证任何其他线程将会获取。- 返回:
-
如果可能有其他线程正在等待获取,则返回
true
-
hasContended
public final boolean hasContended()查询是否有任何线程曾经争夺获取此同步器;也就是说,是否曾经阻塞过获取方法。在此实现中,此操作在常量时间内返回。
- 返回:
-
如果曾经存在争夺,则返回
true
-
getFirstQueuedThread
返回队列中第一个(等待时间最长)的线程,如果当前没有线程在排队则返回null
。在此实现中,此操作通常在常量时间内返回,但如果其他线程同时修改队列,则可能会迭代争用。
- 返回:
-
队列中第一个(等待时间最长)的线程,如果当前没有线程在排队则返回
null
-
isQueued
如果给定线程当前在队列中,则返回true。此实现遍历队列以确定给定线程是否存在。
- 参数:
-
thread
- 线程 - 返回:
-
如果给定线程在队列中则返回
true
- 抛出:
-
NullPointerException
- 如果线程为null
-
hasQueuedPredecessors
public final boolean hasQueuedPredecessors()查询是否有任何线程等待获取的时间比当前线程长。调用此方法等效于(但可能比以下方式更有效):
getFirstQueuedThread() != Thread.currentThread() && hasQueuedThreads()
请注意,由于中断和超时导致的取消可能随时发生,因此返回
true
并不保证其他线程将在当前线程之前获取。同样,可能会出现另一个线程在此方法返回false
后赢得排队的竞争,因为队列为空。此方法设计用于公平同步器,以避免插队。如果此方法返回
true
(除非这是可重入获取),则公平同步器的tryAcquire(int)
方法应返回false
,其tryAcquireShared(int)
方法应返回负值。例如,公平、可重入、独占模式同步器的tryAcquire
方法可能如下所示:protected boolean tryAcquire(int arg) { if (isHeldExclusively()) { // 可重入获取;增加持有计数 return true; } else if (hasQueuedPredecessors()) { return false; } else { // 尝试正常获取 } }
- 返回:
-
如果存在排在当前线程前面的排队线程,则返回
true
;如果当前线程在队列头部或队列为空,则返回false
- 自1.7起
- 1.7
-
getQueueLength
public final int getQueueLength()返回等待获取的线程数的估计值。该值仅是一个估计,因为在此方法遍历内部数据结构时,线程的数量可能会动态变化。此方法设计用于监视系统状态,而不是用于同步控制。- 返回:
- 估计的等待获取线程数
-
getQueuedThreads
返回一个包含可能正在等待获取的线程的集合。由于在构造此结果时实际线程集可能会动态变化,因此返回的集合仅是最佳估计。返回的集合的元素没有特定顺序。此方法旨在便于构建提供更广泛监控功能的子类。- 返回:
- 线程的集合
-
getExclusiveQueuedThreads
返回一个包含可能正在等待以独占模式获取的线程的集合。其具有与getQueuedThreads()
相同的属性,只是它仅返回由于独占获取而等待的线程。- 返回:
- 线程的集合
-
toString
返回一个标识此同步器及其状态的字符串。状态在括号中,包括字符串"State ="
,后跟getState()
的当前值,以及根据队列是否为空的情况,要么是"nonempty"
要么是"empty"
。 -
owns
查询给定的 ConditionObject 是否使用此同步器作为其锁。- 参数:
-
condition
- 条件 - 返回:
-
如果拥有则返回
true
- 抛出:
-
NullPointerException
- 如果条件为 null
-
hasWaiters
查询是否有任何线程正在等待与此同步器关联的给定条件。请注意,因为超时和中断可能随时发生,所以返回true
并不保证将来的signal
会唤醒任何线程。此方法主要设计用于监视系统状态。- 参数:
-
condition
- 条件 - 返回:
-
如果有任何等待线程则返回
true
- 抛出:
-
IllegalMonitorStateException
- 如果没有持有独占同步 -
IllegalArgumentException
- 如果给定条件与此同步器不相关 -
NullPointerException
- 如果条件为 null
-
getWaitQueueLength
返回与此同步器关联的给定条件上正在等待的线程数的估计值。请注意,因为超时和中断可能随时发生,所以估计仅作为实际等待线程数量的上限。此方法设计用于监视系统状态,而不是用于同步控制。- 参数:
-
condition
- 条件 - 返回:
- 等待线程的估计数量
- 抛出:
-
IllegalMonitorStateException
- 如果没有持有独占同步 -
IllegalArgumentException
- 如果给定条件与此同步器不相关 -
NullPointerException
- 如果条件为 null
-
getWaitingThreads
public final Collection<Thread> getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition) 返回一个包含可能正在等待与此同步器关联的给定条件的线程的集合。由于在构造此结果时实际线程集可能会动态变化,因此返回的集合仅是最佳估计。返回的集合的元素没有特定顺序。- 参数:
-
condition
- 条件 - 返回:
- 线程的集合
- 抛出:
-
IllegalMonitorStateException
- 如果没有持有独占同步 -
IllegalArgumentException
- 如果给定条件与此同步器不相关 -
NullPointerException
- 如果条件为 null
-