写在前面
CAS(Compare and Swap)
比较并交换。对一个值进行赋值的原子操作,底层调用的是sun.misc.Unsafe类的一个native方法,通过JNI调用CPU底层指令实现。
重入
同一个线程可以多次获取同一把锁。
AQS队列
遵循FIFO原则的一个双向链表(Node),未抢占到锁的线程会以尾插法的方式放入链表中。
手把手一步一步进行源码分析
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
} finally {
lock.unlock();
}
}
一、lock分析
通过构造方法可以看出,默认采用的是非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
假设同时有两个线程ThreadA、ThreadB同时调用lock方法
// 原始代码
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
// 加了注释后的代码
final void lock() {
// 通过CAS抢占锁, 假设ThreadA成功将state的值从0设置为1
if (compareAndSetState(0, 1))
// 抢占成功, 设置exclusiveOwnerThread为ThreadA线程
setExclusiveOwnerThread(Thread.currentThread());
// 抢占锁成功, 退出lock方法, 执行ThreadA的业务逻辑
else
// ThreadA 修改 state状态为1之后, ThreadB设置失败执行以下逻辑
acquire(1);
}
进入acquire(1)方法分析
// 原始代码
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 加了注释后的代码
public final void acquire(int arg) {
// 预分析
/* !tryAcquire: 返回true时,if 条件之后没有其他逻辑,我们可以猜测,应该是获取到了锁,
至于如何获取到锁的,后面继续进行源码分析 */
// addWaiter: 初始化链表的头尾节点和创建当前线程的node节点并设置为尾节点(尾插法)
/* acquireQueued: 自选通过上面的tryAcquire抢占锁, 如果抢占失败,
则阻塞当前线程(通过LockSupport.park()), 具体后面分析 */
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 中断标记传递
selfInterrupt();
}
进入tryAcquire方法后调用的是非公平锁的nonfairTryAcquire方法, 所以直接看nonfairTryAcquire
// 算了还是粘出来吧
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// 原始代码
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);
return true;
}
return false;
}
// 加了注释的代码
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread(); // 获取当前线程
int c = getState(); // 获取state值
// 如果为0时, 说明ThreadA已经执行玩逻辑调用unlock方法
if (c == 0) {
// cas抢占锁, 这段代码熟悉吧! 和上面lock方法一模一样的操作
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true; // 返回true, 抢占锁成功
}
}
/* 如果不为0时,则判断exclusiveOwnerThread是否和当前线程是同一个线程, 如果是就代表重入,
重入逻辑就做了state = state + acquires 进行累加重入次数 */
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; // 返回false, 上一个放是做了取反的,我们继续往下分析
}
addWaiter(Node.EXCLUSIVE) 分析
// 原始代码
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;
}
}
enq(node);
return 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;
// CAS操作, 将尾节点设置成当前线程的节点, 知道为什么不先将尾节点的下一个节点设置成node吗?
因为当cas操作失败之后, 不会影响到原来链表的结构。(好吧,你肯定知道,我就喜欢多嘴)
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 初始化头尾节点, 并自选通过cas尾插当前线程节点(上面不进if 或者 cas 失败我不能不管是吧)
enq(node);
return node;
}
enq(node) 分析
// 原始代码
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
// 加了注释的代码
private Node enq(final Node node) {
for (;;) {
Node t = tail;
// tail == null 时, cas初始化头尾节点, 设置失败则for自旋重新设置
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
// cas设置当前线程节点为尾节点, 设置失败则for自旋重新设置
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 分析
// 原始代码
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);
}
}
// 加了注释的代码
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取当前线程节点的上一个节点
final Node p = node.predecessor();
// 如果上一个节点为head节点, 通过上面分析tryAcquire方法进行cas抢占锁
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);
}
}
shouldParkAfterFailedAcquire(p, node) 分析
// 原始代码
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
// 加了注释的代码
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true; // 只有节点waitStatus=SIGNAL时才会返回true
if (ws > 0) {
do {
// 循环去除处于CANCELLED状态下的节点
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// cas设置pred.waitStatus为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt() 分析
private final boolean parkAndCheckInterrupt() {
// 阻塞当前线程 LockSupport.park(this);
return Thread.interrupted();
}
二、unlock分析
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
// 递减state(递减重入次数), 为0时返回true
if (tryRelease(arg)) {
// 获取头节点
Node h = head;
if (h != null && h.waitStatus != 0)
// 唤醒处于阻塞状态下的线程
unparkSuccessor(h);
return true;
}
return false;
}