ReentrantLock 原理深度解析 — 基于jdk1.8
ReentrantLock 主要讲解 lock 和 unlock 方法。 看看他上锁 锁等待 释放锁 重入性 是如何实现的 主要看注解吧
1.首先看初始化方法
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync(); // 默认选择非公平锁
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ?
new FairSync() // 非平锁
:
new NonfairSync(); // 公平锁
}
这里提到了两内部类
1. new FairSync() ;
2. new NonfairSync();
他们的主要区别 在于 lock方法
1. NonfairSync 会首先尝试获取锁 获取失败之后 会进被加入列队进入等待状态、
2. FairSync 则先判断锁是否被其他线程占有 如果是的话 进入队列尾部等待
他们均继承了 ReentrantLock.Sync 类, ReentrantLock.Sync 类 又继承了 AbstractQueuedSynchronizer
1. ReentrantLock.Sync 类 对一些公共方法
2. AbstractQueuedSynchronizer 内部维护着一个由双向链表实现的队列 用来记录等待锁释放的线程,
实际操作中 NonfairSync 的使用比较多 这里针对NonfairSync 进行研读
NonfairSync :
/**
* 非公平锁的同步对象
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
- 先看lock方法
final void lock() {
// 通过原子操作 改变上锁状态
if (compareAndSetState(0, 1)) // 变更成功
setExclusiveOwnerThread(Thread.currentThread()); // 设置持有者为当前线程
else // 变更成功
acquire(1);
}
按代码顺序往下卡
1.1 compareAndSetState 方法
private static final Unsafe unsafe = Unsafe.getUnsafe();
static {
try {
// 获取偏移量
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
}
/**
* 通过原子操作 改变上锁状态
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this 调用本地方法 实现硬件级别的原子操作 cas
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
Unsafe :
1. CAS的核心类 (CAS 比较并交换)
2. 通过本地方法 操作内存 实现 cas
3. 一知半解的情况下 不要操作此类
1.2 setExclusiveOwnerThread(Thread.currentThread()); 没什么好说的
1.3 AbstractQueuedSynchronizer.acquire();
/**
* Acquires in exclusive mode, ignoring interrupts. Implemented
* by invoking at least once {@link #tryAcquire},
* returning on success. Otherwise the thread is queued, possibly
* repeatedly blocking and unblocking, invoking {@link
* #tryAcquire} until success. This method can be used
* to implement method {@link Lock#lock}.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 再次尝试上锁 回到了 NonfairSync.tryAcquire 方法, tryAcquire 调用了 Sync.nonfairTryAcquire方法
acquireQueued(
addWaiter(Node.EXCLUSIVE), // 链表尾部添加节点
arg
)
)
selfInterrupt();
}
1.3.1 nonfairTryAcquire:
/**
* 判断 reentranLock 状态 是否被锁住(state ?= 0)
* <p>如果没被锁住尝试 原子性上锁 失败返回false</>
* <p>如果被锁住 判断是否是当前线程持有锁(重入锁的实现) 如果是 state + 1
* (信号量 记录该线程持有锁的次数。 该线程每次释放所 信号量 -1。 信号量为零 代表 锁被真正释放)</>
* <p>else 返回false</p>
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread(); // 获取当前线程
int c = getState(); // 获取当锁的状态
if (c == 0) { // 如果锁已被经释放 再次尝试获取锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 如果当前线程为锁的拥有者
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); // 累加 state 的值 此段代码 实现了重入锁
return true;
}
return false;
}
1.3.2 addWaiter代码:
/**
*
* 把当前线程加入队列 尾部
*
* 负责队列初始化
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) { // 列队尾部不为空
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 列队尾部为空 或者 CAS 操作失败
enq(node);
return node;
}
/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // 尾部不为空 不断尝试 CAS 操作
if (compareAndSetHead(new Node()))
tail = head;
} else { // 尾部为空 尝试构建表结构
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
1.3.3 acquireQueued
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { // 判断当前节点的 前驱节点 是否为队列头部 如果是 再次尝试上锁(如果头部节点 已经释放所, 则使当前线程成为持有者 并且设置自己为 头部。 同时释放前驱节点)
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt() // 进入等待状态 等待唤醒
)
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node); // TODO: 2018/1/29 抛出异常 才会走的到这里。 源码在下面
}
}
/**
* 检查 是否需要阻塞当前线程
* Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev.
*
* @param pred node's predecessor holding status
* @param node the node
* @return {@code true} if thread should block
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/* 后继节点在等待唤醒 也就是当前节点需要进入等待状态了
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) { // 前驱节点被取消
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry. // 前任被取消则 将前驱节点移出列队
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/* 设置前驱节点为 SIGNAL 标记自己为等待唤醒 下次循环到这里之前 如果没有成功拥有锁, 则会进入 if (ws == Node.SIGNAL) 代码段
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); // 又是一个底层类 实现线程等待
return Thread.interrupted(); // 返回并 取消等待状态
}
/**
* Cancels an ongoing attempt to acquire.
* 列队等待中 抛出异常会调用此方法
* @param node the node
*/
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null; // 释放线程
// 前驱节点已被取消 重新定义前驱节点
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED; // 取消当前线程 所属的节点(标记为取消), 没有使用 cas 因为 其他线程 不会干扰这里
// If we are the tail, remove ourselves. 如果我们是尾巴,就把自己弄走
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
// 如果node既不是tail,又不是head的后继节点
// 则将node的前继节点的waitStatus置为SIGNAL
// 并使node的前继节点指向node的后继节点(相当于将node从队列中删掉了)
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
// 如果node是head的后继节点,则直接唤醒node的后继节点
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
/** 唤醒后继节点
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0) //置零当前线程所在的结点状态,允许失败。
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread); // 唤醒下级节点
}
lock 方法的实现 大概就以上的内容
通过以上的内容 大概可以猜测出 unlock 是如何操作的。。。 那么 先写到这里。。。。
剩下的。。。。 猜啊