从ReetrantLock到AQS
前言
使用state
属性表示锁的状态(无锁、已锁)
- 为了保证
state
属性值在多线程之间可见,使用了volatile
修饰 - 为了安全,在多线程抢占锁时使用
CAS
修改state
的值,以保证原子性 state
==0
为无锁状态;由于可重入,每重入一次+1
,已加锁状态由state
>0
表示
加锁
抢到锁后
-
保存持有锁的线程,也就是当前线程
-
方法结束返回
未抢占到锁后
-
线程对象被封装成
Node
,并追加到双向链表的队尾
-
加入到队列中后,如果当前线程的节点是队列中第一个有效节点,在阻塞之前会尝试进行一次获取锁的操作
双向队列
head
指向的Node
中线程对象为空(因为创建队列第一个节点时是直接new Node()
),因此队列头节点的下一个节点才是有效的节点 -
然后当前线程会阻塞在一个循环中(使用
LockSupport#park
),等待被唤醒
-
持有锁的线程a释放锁后,会将队列中第一个线程b唤醒,由于线程b是阻塞在循环中,被唤醒后会继续通过调用
tryAcquire
尝试获取锁
解锁
- 更新
state
值state = state - 1;
- 将双向链表中第一个阻塞的线程唤醒(使用
LockSupport#unpark
)
锁的公平性与非公平性
公平锁
- 线程抢占锁时若有其他线程排队在队列中,则当前线程直接加入队列
- 没有排队,则尝试抢占锁(使用
CAS
尝试修改state
值)
非公平锁
-
直接尝试抢占锁(使用
CAS
尝试修改state
值),不论是否有线程排队在队列中
-
ReetrantLock默认使用非公平锁(
NonfairSync
)