主要对之前的学习进行一个补充。

AbstractQueuedSynchronizer是实现同步容器的基础。在JUC中是一个非常主要的类,JDK文档是这么描述的:

为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 ​​getState()​​、​​setState(int)​​ 和 ​​compareAndSetState(int, int)​​ 方法来操作以原子方式更新的 int 值。

 有这么几个重点:
1.FIFO;

2.依靠单个原子int值来表示状态;

    

再看AbstractQueuedSynchronizer_取对象

3.子类必须定义更改此状态的受保护方法;

4.基于模板;

在如何使用还有这样一段描述:

为了将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 ​​getState()​​、​​setState(int)​​ 和/或 ​​compareAndSetState(int, int)​​ 方法来检查和/或修改同步状态来实现的:

  • ​​tryAcquire(int)​​
  • ​​tryRelease(int)​​
  • ​​tryAcquireShared(int)​​
  • ​​tryReleaseShared(int)​​
  • ​​isHeldExclusively()​​

默认情况下,每个方法都抛出 ​​UnsupportedOperationException​​。这些方法的实现在内部必须是线程安全的,通常应该很短并且不被阻塞。定义这些方法是使用此类的 唯一受支持的方式。其他所有方法都被声明为 final,因为它们无法是各不相同的。

 也就是说只有5个方法我们可以自己定义,其它的方法均为final。独占式使用tryAcquire(int)和tryRelease(int),共享式使用tryAcquireShared(int)和tryReleaseShared(int)。

API如下:

方法摘要

​ 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​​ 

          返回一个 collection,其中包含可能正在等待与此同步器有关的给定条件的那些线程。

​ int​

getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject​​ 

          返回正在等待与此同步器有关的给定条件的线程数估计值。

​ boolean​

hasContended()​​ 

          查询是否其他线程也曾争着获取此同步器;也就是说,是否某个 acquire 方法已经阻塞。

​ boolean​

hasQueuedThreads()​​ 

          查询是否有正在等待获取的任何线程。

​ boolean​

hasWaiters(AbstractQueuedSynchronizer.ConditionObject​​ 

          查询是否有线程正在等待给定的、与此同步器相关的条件。

​protected  boolean​

isHeldExclusively()​​ 

          如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回 ​​true​​。

​ boolean​

isQueued(Thread​​ 

          如果给定线程的当前已加入队列,则返回 true。

​ boolean​

owns(AbstractQueuedSynchronizer.ConditionObject​​ 

          查询给定的 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)​​ 

          试图设置状态来反映共享模式下的一个释放。

 ReentrantLock就是基于AQS实现的,可以看看ReentrantLock的lokc()方法:

再看AbstractQueuedSynchronizer_子类_02

这个方法交给了同步器去处理,看看这个同步器:

再看AbstractQueuedSynchronizer_子类_03

继承了AQS,而且lock()方法还是abstact的。这是因为ReentrantLock有公平和非公平两种情况:

再看AbstractQueuedSynchronizer_等待队列_04

下面来看看NonfairSync中的lock()方法:

再看AbstractQueuedSynchronizer_子类_05

使用CAS设置当前状态,设置当前线程为独占线程。重点看这个acquire()方法。这个acquire()方法其实是AQS中的方法:

再看AbstractQueuedSynchronizer_子类_06

acquire()方法是这么描述的:

acquire

public final void acquire(int arg)

以独占模式获取对象,忽略中断。通过至少调用一次 ​​tryAcquire(int)​​ 来实现此方法,并在成功时返回。否则在成功之前,一直调用 ​​tryAcquire(int)​​ 将线程加入队列,线程可能重复被阻塞或不被阻塞。可以使用此方法来实现 ​​Lock.lock()​​ 方法。

 

参数:

​arg​​ - acquire 参数。此值被传送给 ​​tryAcquire(int)​​,但它是不间断的,并且可以表示任何内容。

 这是一个final方法,而在AQS中acquire()内部调用了tryAcquire()方法,上面也介绍过了,tryAcquire()方法需要被重写。看看实现的tryAcquire()方法:

再看AbstractQueuedSynchronizer_取对象_07

/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取状态
int c = getState();
if (c == 0) {
//判断当前线程是否获取到锁
if (compareAndSetState(0, acquires)) {
//设置为当前线程
setExclusiveOwnerThread(current);
return true;
}
}
//如果是当前线程开始判断重入
else if (current == getExclusiveOwnerThread()) {
//状态加
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//更新状态
setState(nextc);
//获取成功
return true;
}
return false;
}

反过来再看acquire()方法,如果获取不成功就要执行acquireQueued(addWaiter(Node.EXCLUSIVE),arg))方法。之前也介绍过,内部会维护一个FIFO,这个方法就是放进等待队列里面。看看AQS中的addWaiter(Node node)方法:

再看AbstractQueuedSynchronizer_等待队列_08

再看看acquireQueued()方法,刚刚直接将节点插入到了等待队列中,但是当前线程还没有被阻塞