|
|||||||||
摘要: 嵌套 | 字段 | 构造方法 | 方法 | 详细信息: 字段 | 构造方法 | 方法 |
java.util.concurrent.locks
类 AbstractQueuedSynchronizer
java.lang.Object java.util.concurrent.locks.AbstractQueuedSynchronizer
- 所有已实现的接口:
- Serializable
-
public abstract class AbstractQueuedSynchronizer
- extends Object
- implements Serializable
为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁定和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()
、setState(int)
和 compareAndSetState(int, int)
方法来操作以原子方式更新的 int 值。
应该将子类定义为非公共内部帮助器类,可用它们来实现其封闭类的同步属性。类 AbstractQueuedSynchronizer 没有实现任何同步接口。而是定义了诸如 acquireInterruptibly(int)
之类的一些方法,在适当的时候可以通过具体的锁定和相关同步器来调用它们,以实现其公共方法。
此类支持默认的独占 模式和共享 模式之一,或者二者都支持。处于独占模式下时,其他线程试图获取该锁定将无法取得成功。在共享模式下,多个线程获取某个锁定可能(但不是一定)会获得成功。此类并不“了解”这些不同,除了机械地意识到当在共享模式下成功获取某一锁定时,下一个等待线程(如果存在)也必须确定自己是否可以成功获取该锁定。处于不同模式下的等待线程可以共享相同的 FIFO 队列。通常,实现子类只支持其中一种模式,但两种模式都可以在(例如)ReadWriteLock
中发挥作用。只支持独占模式或者只支持共享模式的子类不必定义支持未使用模式的方法。
此类通过支持独占模式的子类定义了一个嵌套的 AbstractQueuedSynchronizer.ConditionObject
类,可以将这个类用作 Condition
实现。isHeldExclusively()
方法将报告同步对于当前线程是否是独占的;使用当前 getState()
值调用 release(int)
方法则可以完全释放此对象;如果给定保存的状态值,那么 acquire(int)
方法可以将此对象最终恢复为它以前获取的状态。没有别的 AbstractQueuedSynchronizer 方法创建这样的条件,因此,如果无法满足此约束,则不要使用它。AbstractQueuedSynchronizer.ConditionObject
的行为当然取决于其同步器实现的语义。
此类为内部队列提供了检查、检测和监视方法,还为 condition 对象提供了类似方法。可以根据需要使用用于其同步机制的 AbstractQueuedSynchronizer 将这些方法导出到类中。
此类的序列化只存储维护状态的基础原子整数,因此已序列化的对象拥有空的线程队列。需要可序列化的典型子类将定义一个 readObject 方法,该方法在反序列化时将此对象恢复到某个已知初始状态。
使用
为了将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 getState()
、setState(int)
和/或 compareAndSetState(int, int)
方法来检查和/或修改同步状态来实现的:
UnsupportedOperationException
。这些方法的实现在内部必须是线程安全的,通常应该很短并且不被阻塞。定义这些方法是使用此类的惟一 受支持的方式。其他所有方法都被声明为 final,因为它们无法是各不相同的。
即使此类基于内部的某个 FIFO 队列,它也无法强行实施 FIFO 获取策略。独占同步的核心采用以下形式:
Acquire: while (!tryAcquire(arg)) { enqueue thread if it is not already queued; possibly block current thread; } Release: if (tryRelease(arg)) unblock the first queued thread;(共享模式与此类似,但可能涉及级联信号。)
因为要在加入队列之前检查线程的获取状况,所以新获取的线程可能闯入 其他被阻塞的和已加入队列的线程之前。不过如果需要,可以内部调用一个或多个检查方法,通过定义 tryAcquire 和/或 tryAcquireShared 来禁用闯入。特别是 getFirstQueuedThread()
没有返回当前线程的时候,严格的 FIFO 锁定可以定义 tryAcquire 立即返回 false。只有 hasQueuedThreads()
返回 true 并且 getFirstQueuedThread 不是当前线程时,更好的非严格公平的版本才可能会立即返回 false;如果 getFirstQueuedThread 不为 null 并且不是当前线程,则产生的结果相同。出现进一步的变体也是有可能的。
对于默认闯入(也称为 greedy、renouncement 和 convoy-avoidance)策略,吞吐量和可伸缩性通常是最高的。尽管无法保证这是公平的或是无偏向的,但允许更早加入队列的线程先于更迟加入队列的线程再次争用资源,并且相对于传入的线程,每个参与再争用的线程都有平等的成功机会。此外,尽管从一般意义上说,获取并非“自旋”,它们可以在阻塞之前对用其他计算所使用的 tryAcquire 执行多次调用。在只保持独占同步时,这为自旋提供了最大的好处,但不是这种情况时,也不会带来最大的负担。如果需要这样做,那么可以使用“快速路径”检查来先行调用 acquire 方法,以这种方式扩充这一点,如果可能不需要争用同步器,则只能通过预先检查 hasContended()
和/或 hasQueuedThreads()
来确认这一点。
通过特殊化其同步器的使用范围,此类为部分同步化提供了一个有效且可伸缩的基础,同步器可以依赖于 int 型的 state、acquire 和 release 参数,以及一个内部的 FIFO 等待队列。这些还不够的时候,可以使用 atomic
类、自己的定制 Queue
类和 LockSupport
阻塞支持,从更低级别构建同步器。
用例
以下是一个非再进入的互斥锁定类,它使用值 0 表示未锁定状态,使用 1 表示锁定状态。它还支持一些条件并公开了一个检测方法:
class Mutex implements Lock, java.io.Serializable { // Our internal helper class private static class Sync extends AbstractQueuedSynchronizer { // Report whether in locked state protected boolean isHeldExclusively() { return getState() == 1; } // Acquire the lock if state is zero public boolean tryAcquire(int acquires) { assert acquires == 1; // Otherwise unused return compareAndSetState(0, 1); } // Release the lock by setting state to zero protected boolean tryRelease(int releases) { assert releases == 1; // Otherwise unused if (getState() == 0) throw new IllegalMonitorStateException(); setState(0); return true; } // Provide a Condition Condition newCondition() { return new ConditionObject(); } // Deserialize 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); } }
- 从以下版本开始:
- 1.5
- 另请参见:
- 序列化表格
嵌套类摘要 | |
---|---|
class |
AbstractQueuedSynchronizer.ConditionObject AbstractQueuedSynchronizer 的 Condition 实现是 Lock 实现的基础。 |
构造方法摘要 | |
---|---|
protected |
AbstractQueuedSynchronizer() 使用初始同步状态 0 来创建一个新的 AbstractQueuedSynchronizer 实例。 |
方法摘要 | |
---|---|
void |
acquire(int arg) 以独占模式获取对象,忽略中断。 |
void |
acquireInterruptibly(int arg) 以独占模式获取对象,如果被中断则中止。 |
void |
acquireShared(int arg) 以共享模式获取对象,忽略中断。 |
void |
acquireSharedInterruptibly(int arg) 以共享模式获取对象,如果被中断则中止。 |
protected boolean |
compareAndSetState(int expect, int update) 如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。 |
Collection<Thread> |
getExclusiveQueuedThreads() 返回包含可能正以独占模式等待获取的线程 collection。 |
Thread |
getFirstQueuedThread() 返回队列中第一个(等待时间最长的)线程,如果目前没有将任何线程加入队列,则返回 null。 |
Collection<Thread> |
getQueuedThreads() 返回包含可能正在等待获取的线程 collection。 |
int |
getQueueLength() 返回等待获取的线程数估计值。 |
Collection<Thread> |
getSharedQueuedThreads() 返回包含可能正以共享模式等待获取的线程 collection。 |
protected int |
getState() 返回同步状态的当前值。 |
Collection<Thread> |
getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition) 返回一个 collection,其中包含可能正在等待与此同步器有关的给定条件的那些线程。 |
int |
getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition) 返回正在等待与此同步器有关的给定条件的线程数估计值。 |
boolean |
hasContended() 查询是否其他线程也曾争着获取此同步器;也就是说,是否某个 acquire 方法已经阻塞。 |
boolean |
hasQueuedThreads() 查询是否有正在等待获取的任何线程。 |
boolean |
hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition) 查询是否有线程正在等待给定的、与此同步器相关的条件。 |
protected boolean |
isHeldExclusively() 如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回 true。 |
boolean |
isQueued(Thread thread) 如果给定线程目前已加入队列,则返回 true。 |
boolean |
owns(AbstractQueuedSynchronizer.ConditionObject condition) 查询给定的 ConditionObject 是否使用了此同步器作为其锁定。 |
boolean |
release(int arg) 以独占模式释放对象。 |
boolean |
releaseShared(int arg) 以共享模式释放对象。 |
protected void |
setState(int newState) 设置同步状态的值。 |
String |
toString() 返回标识此同步器及其状态的字符串。 |
protected boolean |
tryAcquire(int arg) 试图在独占模式下获取对象状态。 |
boolean |
tryAcquireNanos(int arg, long nanosTimeout) 试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。 |
protected int |
tryAcquireShared(int arg) 试图在共享模式下获取对象状态。 |
boolean |
tryAcquireSharedNanos(int arg, long nanosTimeout) 试图以共享模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。 |
protected boolean |
tryRelease(int arg) 试图设置状态来反映独占模式下的一个释放。 |
protected boolean |
tryReleaseShared(int arg) 试图设置状态来反映共享模式下的一个释放。 |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
构造方法详细信息 |
---|
AbstractQueuedSynchronizer
protected AbstractQueuedSynchronizer()
- 使用初始同步状态 0 来创建一个新的 AbstractQueuedSynchronizer 实例。
方法详细信息 |
---|
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)
-
试图在独占模式下获取对象状态。此方法应该查询是否允许它在独占模式下获取对象状态,如果允许,则获取它。
此方法总是由执行 acquire 的线程来调用。如果此方法报告失败,则 acquire 方法可以将线程加入队列(如果还没有将它加入队列),直到获得其他某个线程释放了该线程的信号。可以用此方法来实现
Lock.tryLock()
方法。默认实现将抛出
UnsupportedOperationException
-
-
- 参数:
-
arg
- acquire 参数。该值总是传递给 acquire 方法的那个值,或者是因某个条件等待而保存在条目上的值。该值是不间断的,并且可以表示任何内容。 - 返回:
- 如果成功,则返回 true。在成功的时候,此对象已经被获取。
- 抛出:
-
IllegalMonitorStateException
- 如果正在进行的获取操作将在非法状态下放置此同步器。必须以一致的方式抛出此异常,以便同步正确运行。 -
UnsupportedOperationException
- 如果不支持独占模式
tryRelease
protected boolean tryRelease(int arg)
-
试图设置状态来反映独占模式下的一个释放。
此方法总是由正在执行释放的线程调用。
默认实现将抛出
UnsupportedOperationException
-
-
- 参数:
-
arg
- release 参数。该值总是传递给 release 方法的那个值,或者是因某个条件等待而保存在条目上的当前状态值。该值是不间断的,并且可以表示任何内容。 - 返回:
- 如果此对象现在处于完全释放状态,从而使等待的线程都可以试图获得此对象,则返回 true;否则返回 false。
- 抛出:
-
IllegalMonitorStateException
- 如果正在进行的释放操作将在非法状态下放置此同步器。必须以一致的方式抛出此异常,以便同步正确运行。 -
UnsupportedOperationException
- 如果不支持独占模式
tryAcquireShared
protected int tryAcquireShared(int arg)
-
试图在共享模式下获取对象状态。此方法应该查询是否允许它在共享模式下获取对象状态,如果允许,则获取它。
此方法总是由执行 acquire 线程来调用。如果此方法报告失败,则 acquire 方法可以将线程加入队列(如果还没有将它加入队列),直到获得其他某个线程释放了该线程的信号。
默认实现将抛出
UnsupportedOperationException
-
-
- 参数:
-
arg
- acquire 参数。该值总是传递给 acquire 方法的那个值,或者是因某个条件等待而保存在条目上的值。该值是不间断的,并且可以表示任何内容。 - 返回:
- 在失败时返回负值,在独占成功时返回 0,在非独占成功时也返回一个正值,在这种情况下,后续等待线程必须检查对象的可用性。(支持三种不同的返回值使得此方法可以在只是有时以独占方式获取对象的上下文中使用。)在成功的时候,此对象已经被获取。
- 抛出:
-
IllegalMonitorStateException
- 如果正在进行的获取操作将在非法状态下放置此同步器。必须以一致的方式抛出此异常,以便同步正确运行。 -
UnsupportedOperationException
- 如果不支持共享模式
tryReleaseShared
protected boolean tryReleaseShared(int arg)
-
试图设置状态来反映共享模式下的一个释放。
此方法总是由正在执行释放的线程调用。
默认实现将抛出
UnsupportedOperationException
-
-
- 参数:
-
arg
- release 参数。该值总是传递给 release 方法的那个值,或者是因某个条件等待而保存在条目上的当前状态值。该值是不间断的,并且可以表示任何内容。 - 返回:
- 如果此对象现在处于完全释放状态,从而使正在等待的线程都可以试图获得此对象,则返回 true;否则返回 false。
- 抛出:
-
IllegalMonitorStateException
- 如果正在进行的释放操作将在非法状态下放置此同步器。必须以一致的方式抛出此异常,以便同步正确运行。 -
UnsupportedOperationException
- 如果不支持共享模式