ReentrantLock的实现依赖于Sync。
- Sync是ReentrantLock中的抽象静态内部类,继承自AQS(AbstractQueuedSynchronizer);
- 其子类实现有两个:FairSync、NonfairSync;
- 使用AQS#state来表示持有当前锁对象的线程个数。
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
...
}
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}
...
}
1. lock操作
1.1 NonfairSync实现
NonfairSync#lock()
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
- 通过CAS操作来修改state的状态,
如果state为0,则将其置为1,表示获取锁成功,并将当前线程设置为ownerThread(独占线程); - 获取锁失败,则调用AQS#acquire方法来进行后续处理
AbstractQueuedSynchronizer#acquire(int arg)
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
acquire方法分解为3个步骤:
- 尝试获取锁,成功则退出方法
- 尝试获取锁失败,则调用addWaiter将当前线程以独占Node的形式添加到等待队列尾部
- 调用acquireQueued处理队列中的节点,通过自旋的形式尝试获取锁(内部是无条件for循环实现自旋)
- 中断当前线程interrupt
2.2 FairSync实现
FairSync#lock()
final void lock() {
acquire(1);
}
公平锁lock()操作较为简单,直接调用AQS#acquire(), 具体见非公平锁的描述。
2. tryLock操作
ReentrantLock#tryLock()
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
Sync#nonfairTryAcquire()
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 1.
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 2.
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
公平锁与非公平锁的tryLock()操作是一样的,都是调用Sync#nonfairTryAcquire()
- 获取当前线程,调用AQS#getState()判断锁状态, 锁状态为0,表示无锁状态,通过CAS操作 更新state的值,返回true;
- 锁状态不为0,进一步判断是否为当前独占线程,如果是,则当前线程是重入,更新重入次数nextc,返回true;
- 其他情况属于获取锁失败,返回false
3. unLock操作
非公平锁与公平锁的unLock操作是一样的,都是调用AQS#release()方法。
3.1 AQS#release(int arg)
public final boolean release(int arg) {
// 更新state=(state-arg)标志,state为0 返回true,其他返回false
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
调用AQS#unparkSuccessor()
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
// 1.
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
// 2.
if (s != null)
LockSupport.unpark(s.thread);
}
- 默认是唤醒队首节点s,如果s取消了或者为null,则反转从队尾往队首找,找到第一个waitStatus<=0的节点;
- 节点不为空,则唤醒节点对应的线程
4.总结
- ReentrantLock中加锁/释放锁节点,多次用到CAS操作,这是有硬件保证的并发安全的操作;
- ReentrantLock的lock操作,获取锁失败,创建独占节点,所以ReentrantLock是独占锁。