队列同步器AQS与ReentrantLock
一、AQS模型(volitale + cas + 变体CLH队列) 底层数据结构是双向链表
1.AQS 是基于 volitale 和 CAS 实现的,其中 AQS 中维护一个 valitale 类型的变量 state 来做一个可重入锁的重入次数,加锁和释放锁也是围绕这个变量来进行的。
2.AQS 核心原理
如果被请求的共享资源未被占用,将当前请求资源的线程设置为独占线程,并将共享资源设置为锁定状态。
AQS 使用一个 Volatile 修饰的 int 类型的成员变量 State 来表示同步状态,修改同步状态成功即为获得锁。
Volatile 保证了变量在多线程之间的可见性,修改 State 值时通过 CAS 机制来保证修改的原子性。
如果共享资源被占用,需要一定的阻塞等待唤醒机制来保证锁的分配,AQS 中会将竞争共享资源失败的线程添加到一个变体的 CLH 队列中。
3.CLH 变体队列
3.1 CLH 队列
CLH:Craig、Landin and Hagersten 队列,是 单向链表实现的队列。申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现 前驱节点释放了锁就结束自旋。
通过对 CLH 队列的说明,可以得出以下结论
1)CLH 队列是一个单向链表,保持 FIFO 先进先出的队列特性
2)通过 tail 尾节点(原子引用)来构建队列,总是指向最后一个节点
3)未获得锁节点会进行自旋,而不是切换线程状态
4)并发高时性能较差,因为未获得锁节点不断轮训前驱节点的状态来查看是否获得锁
3.2 CLH 变体队列
AQS 中的队列是 CLH 变体的虚拟双向队列,通过将每条请求共享资源的线程封装成一个节点来实现锁的分配。
相比于 CLH 队列而言,AQS 中的 CLH 变体等待队列拥有以下特性
1)AQS 中队列是个双向链表,也是 FIFO 先进先出的特性
2)通过 Head、Tail 头尾两个节点来组成队列结构,通过 volatile 修饰保证可见性
3)Head 指向节点为已获得锁的节点,是一个虚拟节点,节点本身不持有具体线程
4)获取不到同步状态,会将节点进行自旋获取锁,自旋一定次数失败后会将线程阻塞,相对于 CLH 队列性能较好
4.AQS应用
AQS是英文单词AbstractQueuedSynchronizer的缩写,翻译过来就是队列同步器。
它是构建锁或者其他同步组件的基础框架(ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore等)。
二、ReentrantLock 可重入锁
它是基于经典的 AQS(AbstractQueueSyncronized) 实现的。
1.ReentrantLock特点
1)可重入
2)需要手动加锁、解锁
3)支持设置锁的超时时间
4)支持公平/非公平锁
5)可中断锁
2.ReentrantLock与synchronized的区别