非公平锁(实现类:NonfairSync)
// 默认非公平锁
ReentrantLock lock = new ReentrantLock();
try {
lock.lock();
// do something
} finally {
lock.unlock();
}
加锁:lock.lock();
/**
* 加锁
*/
final void lock() {
// CAS为原子操作,比较STATE值是否为0,是则设置值为1,返回true,否则返回false
if (compareAndSetState(0, 1))
// 设置当前线程为锁的拥有者(仅有一个线程可进入此逻辑)
setExclusiveOwnerThread(Thread.currentThread());
else
// 其他线程,等待,继续获取锁
acquire(1);
}
等待获取锁:acquire(1)
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 尝试获取锁,获取成功则返回true,方法结束
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 获取锁失败后,把当前线程封装为节点,添加到同步等待队列中,开始自旋,直到获取到锁
selfInterrupt(); // 给当前线程添加中断标志,告诉开发者当前线程被中断唤醒,而不是被unpark唤醒
}
尝试获取锁:tryAcquire(arg)
/**
* 尝试获取锁
*/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// 非公平的方式尝试获取锁(就是会插队,后面来的线程可能先获取锁,此处决定了锁的不公平性)
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 状态=0,说明锁已被释放
if (c == 0) {
// 后面进来的线程,可能刚好遇到锁被释放,执行以下CAS,就能获取锁
if (compareAndSetState(0, acquires)) {
// 设置当前线程为锁的拥有者(仅有一个线程可进入此逻辑)
setExclusiveOwnerThread(current);
return true;
}
}
// 判断当前线程是否为锁的拥有者(可重入锁,拥有锁的线程可重复多次获取锁)
else if (current == getExclusiveOwnerThread()) {
// 累加锁的拥有者获取锁的次数
int nextc = c + acquires;
if (nextc < 0) // 溢出
// 当获取锁的次数达到最大Integer.MAX_VALUE,再增加就会溢出,小于0,此时抛错(一般情况下是忘记释放锁导致的)
throw new Error("Maximum lock count exceeded");
// 设置当前锁的获取次数
setState(nextc);
// 获取锁成功
return true;
}
// 获取锁失败
return false;
}
添加线程到队列中:acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
/**
* 把当前线程封装为节点,添加到同步等待队列中
*/
private Node addWaiter(Node mode) {
// mode=null,因此node仅封装了当前线程的信息
Node node = new Node(Thread.currentThread(), mode);
// 获取尾节点
Node pred = tail;
if (pred != null) {
// 当前节点 的 前置节点 指向 尾节点( tail <- node)
node.prev = pred;
// CAS为原子操作,比较尾节点是否为tail,是则设置值为node,返回true,否则返回false
if (compareAndSetTail(pred, node)) {
// 尾节点 的 后置节点 指向 当前节点( tail <-> node),双向链表(环状链表)构建完成,当前节点成功变成尾节点
pred.next = node;
return node;
}
}
// 同步队列为空,初始化同步队列(链表结构)
enq(node);
return node;
}
/**
* 开始自旋,直到获取到锁。
* 1、如果直到获取到锁,线程都没有被park,则返回false
* 2、如果没有获取到锁,且线程
*/
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) && // 获取锁失败后,是否应该被park
parkAndCheckInterrupt()) // 应该被park,park当前线程
interrupted = true; // 当前线程被中断唤醒,而不是被unpark唤醒
}
} finally {
// 如果出现异常,且获取锁失败
if (failed)
// 将当前节点从同步队列中移除
cancelAcquire(node);
}
}
是否阻塞当前线程:shouldParkAfterFailedAcquire(p, node)
/**
* 获取锁失败后,是否应该被park。
* 这个方法可绕了
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// 获取前置节点的等待状态
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* 如果前置节点的等待状态为Node.SIGNAL(值为-1),那么说明当前节点可以被park了
*/
return true;
if (ws > 0) {
/*
* 如果前置节点的等待状态大于0(大于0只有Node.CANCELLED状态,值为1),
* 那么说明前置节点已经被取消掉,需要跳过该节点
*/
do {
// 设置当前节点 的 前置节点 为 前置节点的前置节点(就是把CANCELLED状态的前置节点从队列中扔掉)
node.prev = pred = pred.prev;
// 循环,把前置节点的等待状态为CANCELLED的全部节点都扔掉
} while (pred.waitStatus > 0);
// 直到找到一个等待状态不为CANCELLED的节点,将此前置节点的后置节点设置为当前节点(重新整理等待队列为双向链表)
pred.next = node;
} else {
/*
* 前置节点的状态为不为SIGNAL,也不为CANCELLED,则将前置节点的等待状态设置为SIGNAL,
* 标志当前节点已经准备好被park了,但是不马上进行park,而是让当前节点再一次尝试获取锁,
* 以证明当前节点确实需要被park
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
// 不需要被park
return false;
}
阻塞当前线程:parkAndCheckInterrupt()
/**
* 阻塞当前线程,当前线程被唤醒(可能被unpark唤醒,可能被interrupt唤醒)
*/
private final boolean parkAndCheckInterrupt() {
// 阻塞当前线程
LockSupport.park(this);
// 返回当前线程是否被中断唤醒
return Thread.interrupted();
}
取消获取锁:cancelAcquire(node)
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
// 跳过等待状态为CANCELLED的前置节点
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;
// 如果当前节点是尾节点,则直接移除,把前置节点设为尾节点
if (node == tail && compareAndSetTail(node, pred)) {
// 将前置节点的尾节点设为null
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.
int ws;
if (pred != head // 前置节点 不为 头节点
&& (
// 且(前置节点的等待状态为SIGNAL 或者 等待状态为其他状态,CAS为SIGNAL)
(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)
// 后置节点不为空 且 CAS前置节点 的 后置节点 为 当前节点 的后置节点
compareAndSetNext(pred, predNext, next);
} else {
//
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
释放锁:lock.unlock();