AbstractQueuedSynchronizer,简称AQS,是一个抽象类,它采用了模板方法模式,降低了自定义同步组件实现的门槛。当需要实现自定义的同步组件时,只需要在自定义组件内部定义一个继承AQS的子类,重写自己需要的方法,再调用AQS提供的模板方法即可。AQS向锁的实现者屏蔽了底层的线程唤醒、阻塞、等待的细节,简化了锁的实现方式。
AQS使用一个int成员变量表示同步状态,当该变量为0时表示没有线程获取到锁。当不为0时说明有线程获取到锁。
对于独占式同步状态获取与释放的理解:
AQS内部使用一个双向的FIFO队列进行线程状态的管理,当一个线程使用CAS获取同步状态失败,就会生成一个节点,并将这个节点采用CAS的方式放置到队列末尾,而队列头则是当前获取到同步状态的线程。每一个获取同步状态失败的线程进入FIFO队列成为其中一个节点之后,这个节点都会以死循环的方式获取同步状态。如果获取不到,则会阻塞该节点中的线程,被阻塞线程的唤醒就靠前驱结点的出队或者被中断来实现。
节点进入队列中以死循环的方式获取同步状态的同时,若此时头节点(即获取到同步状态的节点)释放了同步状态,该头节点会唤醒它的后继节点,这个后继结点被唤醒后,首先检查自己的前驱节点是不是头节点,如果是头节点则尝试获取同步状态,如果不是,说明它是被中断唤醒的,则继续进入等待状态,也就是说,这种方式对中断是不敏感的。
《Java并发编程的艺术》一书对该过程的总结如下:
当获取同步状态时,同步器维护一个同步队列,获取同步状态失败的线程都会被加入到同列中并在队列中进行自旋;移出队列(或停止自旋)的条件是前驱结点为头节点并且该节点成功获取到了同步状态。在释放同步状态时,同步器调用tryRelease(int arg)方法释放同步状态,并唤醒头节点的后继节点。