ReentrantLock(默认非公平锁): 可重入锁, 公平所, 非公平锁
lock(公平锁)
public class ReentrantLockDemo {
try {
// 公平锁
ReentrantLock rl = new ReentrantLock(true);
rl.lock();
rl.lock();
// 能够更请清楚看整个执行流程
TimeUnit.SECONDS.sleep(60);
new Thread(() -> {
rl.lock();
}, "aaa").start();
TimeUnit.SECONDS.sleep(60);
new Thread(() -> {
rl.lock();
}, "bbb").start();
} catch (Exception e){
e.printStackTrace();
}
}
public class ReentrantLock implements Lock, java.io.Serializable {
// 初始化
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
// 将 Sync 和 AbstractQueuedSynchronizer 的代码合并了一起说明
static final class FairSync extends Sync extends AbstractQueuedSynchronizer {
// 重入次数
private volatile int state;
// 当前节点超时或者终端, 该节点被取消, 节点永远不会改变状态, 并且取消该节点的线程永远不会再次阻塞
static final int CANCELLED = 1;
// 等待状态值, 后续线程需要暂停
static final int SIGNAL = -1;
// 表示线程处于等待状态, 当前线程处于条件队列行 Condition
static final int CONDITION = -2;
// 表示下一个对象的默认状态值应该无条件传递下去
static final int PROPAGATE = -3;
// 初始化, 用来做线程获取锁的判断
private static final Unsafe unsafe = Unsafe.getUnsafe();
//
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
// !tryAcquire(arg) 第一次进来, 为true
// 当之前任务没有完成, 后面又有任务来获取锁,
// acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 添加到队列中
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 尝试获取锁
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 第一次默认值为 0
int c = getState();
if (c == 0) {
// 第一个任务, hasQueuedPredecessors() 返回false
// compareAndSetState(0, acquires)) 成功获取锁, 并改变 state 值为 1
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
// 表示获取到了锁
return true;
}
}
// 当希望获取锁的任务为同一个时(在 unlock() 未执行), 也可以获取锁(可重入)
else if (current == getExclusiveOwnerThread()) {
// 记录被重入的次数
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// 没有获取锁, 需要将当前任务添加到等待队列中
return false;
}
// 将等待任务添加到 AQS 队列
private Node addWaiter(Node mode) {// 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)) {
// 上个元素的 next 指向当前获取锁的线程
pred.next = node;
return node;
}
}
// 在锁被占用, 后面第一个线程进入, 初始化 node
enq(node);
return node;
}
// 初始化 queue 中第一个 node
// Node t = tail; tail = head; node.prev = t; t.next = node; 循环指引
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
// 初始化头节点, node 的 next 才是真正指向当前来获取的线程,
// 而 waitStatus 记录的也是 next 的状态值
// 在 unlock 中可以发现, 每次唤醒的都是 node 的 next,而且 waitStatus 却是更具当前node 的 waitStatus 来判断
if (compareAndSetHead(new Node()))
// head = new Node();
tail = head;
} else {
// 实际添加元素, node 记录的为当前线程
node.prev = t;
// 第二个获取锁的线程在队列中, 既是头节点也是尾节点(在后面线程添加进入队列时, 由于循环引用)
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
// 入队列, 并将当前线程的 prev 的状态修改为 SIGNAL
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 Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
// 判断当前节点获取锁失败后是否需要挂起
// node 当前线程, pred 当前线程的前置节点
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// 当前置节点状态和当前线程状态一致时(等待), 当前线程需要挂起
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
// 如果前置节点为 cancel 时
do {
// 从队尾遍历, 寻找第一个不为 cancel 的线程作为当前线程的新的前置节点
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// waitStatus must be 0 or PROPAGATE.
// 当前节点的前置节点的状态的改变
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
// 取消正在进行的尝试获取
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
Node pred = node.prev;
// 重新指向新的前置节点
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
Node predNext = pred.next;
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
// 如果当前线程为尾部节点, 则 next 为null
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.
int ws;
// 如果不为头部节点, 并且状态为 signal, 设置前置节点状态为 signal
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 {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
}
}
lock(非公平锁)
非公平锁流程:
① compareAndSetState(0, 1) 判断是否可以获取锁, 成功获取锁, 并设置为独占锁,
② 如果失败, 会再次尝试去获取锁, 在再次获取锁的过程中, 如果前面线程释放了锁, 这会导致前面排队的线程继续排队, 而后到线程却获取到了锁(非公平).
③ 如果失败,则进入等待队列
public class ReentrantLockDemo {
try {
// 公平锁
ReentrantLock rl = new ReentrantLock(false);
rl.lock();
rl.lock();
// 能够更请清楚看整个执行流程
TimeUnit.SECONDS.sleep(60);
new Thread(() -> {
rl.lock();
}, "aaa").start();
TimeUnit.SECONDS.sleep(60);
new Thread(() -> {
rl.lock();
}, "bbb").start();
} catch (Exception e){
e.printStackTrace();
}
}
static final class NonfairSync extends Sync extends AbstractQueuedSynchronizer {
final void lock() {
// 非公平锁, 直接去获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 失败, 添加到队列,
// 再次尝试去获取锁, “非公平”即体现在这里,如果占用锁的线程刚释放锁,state置为0,而排队等待锁的线程还未唤醒时,新来的线程就直接抢占了该锁,那么就“插队”了
//后面逻辑和公平锁一致
acquire(1);
}
}
unlock
public static void main(String[] args) {
ReentrantLock rl = new ReentrantLock(true);
rl.lock();
rl.lock();
TimeUnit.SECONDS.sleep(20);
new Thread(() -> {
rl.lock();
System.out.println(Thread.currentThread().getName());
}, "aaa").start();
TimeUnit.SECONDS.sleep(5);
rl.unlock();
}
public void unlock() {
sync.release(1);
}
// 是否成功释放锁
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
// getState 获取被重入次数
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
// 成功, 清空独占线程
setExclusiveOwnerThread(null);
}
// 更新值
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 释放的 next 节点, 前面 lock 有说明为啥是 next
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);
}