初识
ReentrantLock 类有两个构造函数,一个是默认的不带参数的构造函数,创建一个默认的非公平锁的实现,一个是带参数的构造函数,根据参数 fair 创建一个公平还是非公平的锁。
这里简单的说一下公平锁和非公平锁的定义:
- 公平锁:线程在同步队列中通过先进先出(FIFO)的方式获取锁,每个线程最终都能获取锁。
- 非公平锁:线程可以通过插队的方式抢占锁,抢不到锁就进入同步队列排队。
NonfairSync 类和 FairSync 类继承了 Sync 类,它们三个都是 ReentrantLock 的内部类。
AbstractQueuedSynchronizer,简称 AQS,拥有三个核心组件:
- state:volatile 修饰,线程是否可以获取锁。
- Node:内部队列,双向链表形式,没有抢到锁的对象就进入这个队列。主要字段有:pre 前一个节点,next 下一个节点,thread 线程,waitStatus 线程的状态。
- exclusiveOwnerThread:当前抢到锁的线程。
如下图,简单的了解一下 AQS。
公平锁
在分析公平锁之前,先介绍一下 Sync 类,它是 ReentrantLock 的唯一的属性,在构造函数中被初始化,决定了用公平锁还是非公平锁的方式获取锁。
用以下构造方法创建一个公平锁。沿着 lock.lock()
调用情况一路往下分析。
acquire() 方法主要是干了 3 件事情
- tryAcquire() 尝试获取锁。
- 获取锁失败后,调用 addWaiter() 方法将线程封装成 Node,加入同步队列。
- acquireQueued() 将队列中的节点按自旋的方式尝试获取锁。
tryAcquire() 尝试获取锁,如果线程本身持有锁,则将这个线程重入锁。
hasQueuedPredecessors() 这个方法比较有绅士风度,在 tryAcquire() 方法中被第一个调用,它谦让比自己排队长的线程。