提供一个实现阻塞锁和基于先进先出等待队列的同步器(信号量,事件等等)的框架。这个类被设计出来作为大多数同步器的基类,这些同步器依靠一个单一的原子int值来代表状态。
//volatile int 或 AtomicInteger。
子类必须定义一个protected的方法来改变这个状态,以及定义这个状态在获取和释放此类的对象时的意义。
//获取和释放锁时state值是多少。
基于这些,此类中的其他方法实现所有排队和阻塞的机制。子类可以维护其他的状态字段,但只有那个原子int值被用于同步,这个值通过getState,setState,compareAndSetState方法维护。
子类们应该被定义为一个非public的内部类,用来实现同步属性。AbstractQueuedSynchronizer类不实现任何同步接口。相应的,它定义了一些方法,像acquireInterruptibly,这些方法可以被具体的锁和相关的同步器适当的调用来实现public方法。
//AbstractQueuedSynchronizer的子类一般是内部类,子类的外部类一般是锁,锁提供public方法用来实现同步,这些方法中可能会调用AbstractQueuedSynchronizer定义的方法。
这个类支持默认的exclusive(独占)模式和shared(共享)模式中的一个或全部。当一个线程以独占模式获取了同步器,其他线程对同一个同步器的获取不会成功。共享模式下多个线程获取同步器可能但不一定成功。此类并不清楚这些差异,只是从机制上说,当共享模式下一个线程获取同步器成时,下一个等待线程也必须可以确定它是否可以获取同步器。在不同模式下等待的线程共享同一个先进先出队列。通常,子类的实现仅支持一种模式,但是两种模式都可以发挥作用,例如ReadWriteLock。
//一般继承了AbstractQueuedSynchronizer的类只能是共享模式或独占模式中的一种,但一个锁对象中可以同时存在共享模式同步器和独占模式同步器,就像ReadWriteLock。
支持一种模式的子类不需要定义方法来支持另一种模式。
此类定义了一个ConditionObject内部类,它可以被支持独占模式的子类当作Condition的实现,并为此提供了:isHeldExclusively方法指明了同步器是否被当前线程独占,release方法通过传入getState方法的返回值完全释放这个同步器,和acquire方法,通过保存的state值,最终将这个同步器恢复到之前的占用状态。
//获取和释放时通过传入state值来帮助同步器控制状态。
AbstractQueuedSynchronizer没有其他方法可以创建这种Condition对象,如果这个约束不能得到满足,就不要使用它。ConditionObject的行为取决于其同步器的实现。
此类提供内部队列的检查、检测和监视方法,对Condition对象也提供类似的方法。可以根据需要,继承AbstractQueuedSynchronizer来实现其同步机制。
此类对象在序列化时只存储底层的原子int状态值,所以反序列化出来的对象的线程队列时空的。典型的子类实现序列化的方式是定义readObject方法,这样在反序列化时就能以已知的初始状态恢复对象。
Usage
使用此类作为作为同步器的基类,用getState,setState,compareAndSetState来检查和/或修改这个同步器的state值,以适当地重写以下方法:
- tryAcquire
- tryRelease
- tryAcquireShared
- tryReleaseShared
- isHeldExclusively
这些方法默认抛出UnsupportedOperationException。这些方法的内部实现必须是线程安全的,且通常应该简短、不阻塞。重新定义这些方法是这个类唯一被支持的用途。
//Doug Lea认为AbstractQueuedSynchronizer就是用来让子类重写这些方法的。
其他的方法被声明为final的,因为它们不能独立变化。
即使此类基于内部的先进先出队列,但它不会自动实现先进先出策略。独占模式的核心采用以下形式:
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方法,通过内部调用一个或多个检查方法来避免插队,从而提供一个公平的先进先出获取顺序。特别地,大多数公平的同步器在hasQueuedPredecessors方法(一个被特别设计为用于公平同步器的方法)返回true时使tryAcquire方法返回false。
对于默认插入(也称为greedy,renouncement,convoy-avoidance)策略,吞吐量和可扩展性通常是最高的。虽然这不能保证是公平的或非饥饿的,但较早入队的线程被允许在后入队的线程之前重新竞争,每一次重新竞争都有公平的机会让一个线程取代新进的线程。另外,虽然获取同步器通常不会自旋,但它们可能会在被阻塞之前多次调用tryAcquire方法并穿插着一些计算。
//例如根据一些条件和策略多次调用tryAcquire方法以尝试获取同步器。
当独占模式的同步器只被短暂占用时,这会获自旋的大部分好处,且不会面临非自旋的大部分坏处。
//这种方式可以获得与自旋一样的优点,同时又能避免非自旋的缺点。
如果需要,你可以在调用acquire方法之前做”fast-path”检查来扩展它,例如在同步器很可能没有被争抢的情况下调用hasContended方法和/或hasQueuedThreads方法来做提前检查。
这个类提供了部分专门针对同步器使用的高效、可扩展的基础,它依赖state状态值,acquire和release参数,和内部的先进先出等待队列。如果这还不够,你可以从更底层使用atomic类、你自定义的Queue类和LockSupport的阻塞支持构建同步器。
Usage Examples
这是一个不可重入的互斥锁类,其使用0来代表未被锁定状态,1代表已被锁定状态。虽然不可重入锁不要求严格记录持有线程,但这个类还是这么做了以使监控更容易。它还支持Condition对象并暴露了一个检测方法:
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的latch类,它只需要一个信号来触发。因为latch是非独占的,所以它使用共享的acquire和release方法。
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);
}
}