一、AQS实现加锁
公平锁:hasQueuedPredecessors方法,判断是否有前驱节点
尝试修改同步状态:
- 如果当前同步器里的同步状态标识为0
- 尝试使用CAS修改同步器状态
- 修改成功:获取锁成功,将当前同步器的exclusiveOwnerThread(独占锁线程持有者)设置为当前线程
- 修改失败
- 尝试使用CAS修改同步器状态
- 当前同步器里的同步状态不为0
- 判断当前线程是否是当前同步器的exclusiveOwnerThread(独占锁线程持有者)
- 是,同步状态加1(锁可重入)
- 判断当前线程是否是当前同步器的exclusiveOwnerThread(独占锁线程持有者)
tryAcquire尝试修改同步状态失败情况下:
将当前线程加入队列addWaiter()
- 尝试使用CAS+自旋的方式将当前节点设为尾节点
- CAS入队列
- 自旋CAS入队列
线程入队后,不会马上被阻塞,在阻塞前会再判断一次,是否获取得到锁
- 因为将线程阻塞再唤醒太耗费CPU资源了,且考虑到可能上一个线程可能执行完了同步代码块
- 只有头节点的后面那个节点入队时才会再次尝试去获取锁
将当前节点的前驱节点的waitStatus设置为-1
释放锁后,在唤醒锁的时候需要先判断waitStatus的值
二、AQS实现解锁
- 判断同步器中当前占有锁的线程是否是当前线程
- 是,修改同步器状态为0
- 释放锁成功后,获取head 节点的 next一个节点,使用LockSupport.unpark() 唤醒该节点线程
- head的waitState 必须要 != 0(可唤醒状态)