ReentrantLock¶
公平锁¶
如果当前锁状态
state为 0,说明锁处于闲置状态可以被获取,首先调用
hasQueuedPredecessors方法判断当前线程是否还有前节点 (prev node) 在等待获取锁。如果有,则直接返回 false;如果没有,通过调用
compareAndSetState(CAS)修改 state 值来标记自己已经拿到锁。CAS 执行成功后调用
setExclusiveOwnerThread设置锁的持有者为当前线程。程序执行到现在说明锁获取成功,返回 true;如果当前锁状态
state不为 0,但当前线程已经持有锁(current == getExclusiveOwnerThread()),由于锁是可重入(多次获取)的,则更新重入后的锁状态state += acquires。锁获取成功 返回 true。
非公平锁¶
- 调用 compareAndSetState 方法抢占式加锁,加锁成功则将自己设为持锁线程,并返回
- 若加锁失败,则调用 acquire 方法,将线程置于同步队列尾部进行等待
- 线程在同步队列中成功获取锁,则将自己设为持锁线程后返回
- 若同步状态不为0,且当前线程为持锁线程,则执行重入逻辑
条件¶
await( )¶
- 首先判断线程是否被中断,如果是,直接抛出
InterruptedException,否则进入下一步; - 添加当前线程到条件队列中,然后释放全部资源 / 锁;
- 如果当前节点不在等待队列中,调用
LockSupport.park()阻塞当前线程,直到被unpark或被中断。这里先简单说一下signal方法,在线程接收到 signal 信号后,unpark 当前线程,并把当前线程转移到等待队列中(sync queue)。所以,在当前方法中,如果线程被解除阻塞(unpark),也就是说当前线程被转移到等待队列中,就会跳出while循环,进入下一步; - 线程进入等待队列后,调用
acquireQueued方法获取锁; - 调用
unlinkCancelledWaiters方法检查条件队列中已经取消的节点,并解除它们的链接(这些取消的节点在随后的垃圾收集中被回收掉); - 逻辑处理结束,最后处理中断(抛出
InterruptedException或把忽略的中断补上)。
signal( )¶
- 获取条件队列的首节点,解除首节点的链接(
first.nextWaiter = null;); - 调用
transferForSignal把条件队列的首节点转移到等待队列的尾部。在transferForSignal中,转移节点后,转移的节点没有前继节点,说明当前最后一个等待线程,直接调用unpark()唤醒当前线程。