AQS基本的概念
aqs全称为AbstractQueuedSynchronizer 是一个抽象同步队列,它提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLock、CountDownLatch等。
AQS是一个抽象类,主要是通过继承的方式来使用,它本身没有实现任何的同步接口,仅仅是定义了同步状态的获取以及释放的方法来提供自定义的同步组件。
AQS底层的实现 结合CAS compareAndSwapInt实现
AQS源码解读
NonfairSync 非公平锁
FairSync 公平锁
公平锁与非公平锁最大的区别:就是在做cas操作的是时候加上 !hasQueuedPredecessors()
必须遵循公平竞争
AQS核心参数
1.Node结点 采用双向链表的形式存放正在等待的线程 waitStatus状态、thread等到锁的线程
CANCELLED,值为1,表示当前的线程被取消;
SIGNAL,值为-1,释放资源后需唤醒后继节点;
CONDITION,值为-2, 等待condition唤醒;
PROPAGATE,值为-3,工作于共享锁状态,需要向后传播,比如根据资源是否剩余,唤醒后继节点;
值为0,表示当前节点在sync队列中,等待着获取锁。
- Head 头结点 等待队列的头结点
- Tail 尾结点 正在等待的线程
- State 锁的状态 0 无锁、1已结获取锁, 当前线程重入不断+1
- exclusiveOwnerThread 记录锁的持有
公平锁实现原理图:
非公平锁实现原理图:
Lock锁基本实现原理
Lock锁原理 基于javaAQS类封装 在获取锁的时候AQS类中有一个状态state
+1,当前线程不断重入的时候都会不断1+,当在释放锁的时候state-1;
最终state为0 该锁没有被任何线程获取到,没有抢到锁的线程,会存在一个
双向的链表中。
公平锁与非公平锁在获取锁的时候多了一个判断 (!hasQueuedPredecessors() &
阻塞和唤醒用的apilocksupport,为了这个效率只会唤醒阻塞队列中head节点.next 线程。
AQS中为什么头结点是为空的
头结点可以简单理解就是可以不用参加排队,表示已经获取到锁的线程,已经在aqs类中已经记录绑定获取到锁的线程,所以head结点直接设置为null,防止浪费空间内存。
AQS核心的方法
tryAcquire ---重试获取锁
tryRelease--释放锁
acquireSharedInterruptibly---将当前线程变为阻塞状态
releaseShared ---让等待的线程,被唤醒 同时状态变为0
思考:面试中经如果问AQS的原理怎么回答?AQS如何实现公平锁和非公平锁
每一行代码都有它的涵义,多问一句为什么;别怕,理清思路,一切代码都是数据的流动和转化,耐心一点,慢慢积累!一起加油!!!