AQS
是什么?
AbstractQueueSynchronized 抽象队列同步器。是Java并发编程整个体系的基石,是用来构建锁或者同步组件的基础框架。它通过FIFO队列来实现线程获取资源的排队工作,并通过一个int变量来表示锁的获取状态
锁和同步器的关系
锁是面向锁的使用者,你调用就好了
同步器是面向锁的实现者,比如说你开发的时候需要自定义锁,而同步器可以为你提供实现锁的框架,帮你简化了实现,比如你不用去关心同步状态管理,阻塞队列的排队情况等等
AQS的独占模式和共享模式?
独占意味着同一时刻只有一个线程可以获取同步状态,是互斥锁的基础
共享意味着多个线程可以同时获取同步状态,如 信号量,ReadWriteLock
同步队列
FIFO虚拟双向队列,是CLH队列的变种

想要加锁失败后导致阻塞,阻塞就得排队,那么排队就得有队列
如果资源被占用,那么就得有一定的线程阻塞等待唤醒机制来保证锁的分配。FIFO
AQS为什么采用双向链表?
1 | //基本结构 |
双向链表有两个指针,一个指向前驱节点,一个指向后驱节点
需要前驱节点:
能够实现常量级别的前驱节点查找,增删操作比单向链表更加高效和简单。
AQS在设计的时候为了去避免有线程节点因为异常而导致后置的节点无法被正确唤醒的情况,所以线程节点
在入队的时候都会去判断前置节点的状态,如果这时候没有前驱指针的话,那找到前驱节点就得从头开始遍历
了。

Lock接口里有个lockInterrupt方法,该方法就是说允许加入到阻塞队列里的线程节点被外部所中断。当阻塞队列里的线程被中断后,当线程节点并不会被立马删除,而是会被标记为cancelled状态,然后从尾节点找到离cancelled节点最近的正常节点进行唤醒。同样如果没有前置节点的话,得一个个往下遍历,查询性能很低

按照公平锁的设计,只有头结点的下一个节点才有必要去竞争锁。那么这里就涉及一个前置节点的判断,这个
是单向链表无法实现的。
总的来说就是存在需要高效查找前置节点的需求
ps:上面说的线程节点被外部中断后不会立马删除,那啥时候删除呢

为什么上面说要从尾节点向前遍历,不可以头节点向后遍历?
这个官网没说这么做的原因,网上也没人提为啥这么干。我当时是觉得这样可以减少对头部节点的竞争。因为在高并发情况下,头结点一定是被频繁访问or修改最大的节点,因为头节点是释放锁or被唤醒的首选位置。从尾结点向前遍历就可以减少在头结点上的竞争。