ReentrantLock 源码
ReentrantLock 的 lock 方法源码
ReentrantLock 中的 lock 方法,主要调用内部类 Sync 中的抽象 lock 方法。该方法主要有两套实现,一套是公平锁,一套是非公平锁。
公平锁
final void lock() { acquire(1); }
公平锁中,直接调用 acquire 方法。
非公平锁
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
非公平锁中,首先尝试将 AQS 中的 state 属性从 0 变成 1,如果成功,则代表获取锁资源成功;否则调用 acquire 方法。
ReentrantLock 的 acquire 方法源码
acquire 方法中没有实际的业务处理,都是在调用其他方法。
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
首先调用 tryAcquire 方法,尝试获取锁资源,如果获取成功,则返回 true,方法结束。如果获取失败,则调用 && 后面的方法。
调用 addWaiter() 方法,将线程封装到 Node 节点并添加到队列尾部。
之后再调用 acquireQueued() 方法查看当前排队的 Node 是否在队列的前面,如果在前面,尝试获取锁资源。如果没在前面,线程进入到阻塞状态。
ReentrantLock 的 tryAcquire 方法源码
tryAcquire() 方法分公平锁和非公平锁两套实现,主要做了两件事:
如果 AQS 当前 state 为 0,尝试获取锁资源。
如果 AQS 当前 state 不为 0,查看是否是可重入操作。
公平锁
protected final boolean tryAcquire(int acquires) { // 获取当前线程 final Thread current = Thread.currentThread(); // 获取AQS当前state值 int c = getState(); // 判断state是否为0,为0则代表当前没有线程持有锁 if (c == 0) { // 首先判断是否有线程在排队,如果有,tryAcquie()方法直接返回false // 如果没有,则尝试获取锁资源 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 如果state != 0,则代表有线程持有锁资源 // 判断占有锁的线程是不是当前线程,如果是,则进行可重入操作 else if (current == getExclusiveOwnerThread()) { // 可重入 int nextc = c + acquires; // 检查锁重入是否超过最大值,二进制第一位表示符号 // 01111111 11111111 11111111 11111111 if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
非公平锁
final boolean nonfairTryAcquire(int acquires) { // 获取当前线程 final Thread current = Thread.currentThread(); // 获取AQS当前state值 int c = getState(); // 如果state == 0,说明没有线程占用着当前的锁资源 if (c == 0) { // CAS直接尝试获取锁资源,直接抢锁,不管有没有线程在队列中 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; // 检查锁重入是否超过最大值,二进制第一位表示符号 // 01111111 11111111 11111111 11111111 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); // 修改state当前值 setState(nextc); return true; } return false; }
ReentrantLock 的 addWaiter 方法源码
private Node addWaiter(Node mode) { // 将当前线程封装为Node对象,mode为null,代表互斥锁 Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure // pred指向tail Node pred = tail; if (pred != null) { // 当前线程Node节点的prev指向pred节点 node.prev = pred; // 以CAS方式,尝试将node节点变成tail if (compareAndSetTail(pred, node)) { // 将pred的next指向node pred.next = node; return node; } } // 如果上述方式,CAS操作失败,导致加入到AQS末尾失败,就基于enq的方式添加到AQS队列 enq(node); return node; }
在 tryAcquire() 方法获取锁资源失败之后,首先创建当前线程的 Node 节点,之后将该节点添加到队列尾部。
private Node enq(final Node node) { // 死循环,直到插入成功 for (;;) { Node t = tail; if (t == null) { // Must initialize //如果尾节点为null,说明同步队列还未初始化,则CAS操作新建头节点 if (compareAndSetHead(new Node())) tail = head; } else { // 将node的prev指向当前的tail节点 node.prev = t; // CAS尝试将node变成tail节点 if (compareAndSetTail(t, node)) { // 将之前尾节点的next指向要插入的节点 t.next = node; return t; } } } }
ReentrantLock 的 acquirdQueued 方法源码
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { // 获取node的前一个节点 final Node p = node.predecessor(); // 如果前一个节点为head并尝试获取锁资源 if (p == head && tryAcquire(arg)) { // 尝试获取锁资源成功,将node节点设置为头节点,thread和prev属性置位null setHead(node); // 将之前的头节点的next指向null,帮助快速GC p.next = null; // help GC failed = false; return interrupted; } // 如果前一个节点不是head或者获取锁资源失败 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
// 确保上一个节点的状态是正确的 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; if (ws == Node.SIGNAL) return true; if (ws > 0) { // 循环往前找,找到一个状态小于等于0的节点 do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { // 如果不是-1,但是小于等于0,将状态修改为-1 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
acquireQueued 方***查看当前排队的 Node 的前一个节点是不是 head,如果是,尝试获取锁资源。如果不是或者获取锁资源失败,那么就尝试将当前 Node 的线程挂起。
在挂起线程前,需要确认当前节点的上一个节点的状态是小于等于 0:
如果为 1,代表是取消的节点,不能挂起
如果为 -1,代表挂起当前线程
如果为 -2,-3,需要将状态改为 -1 之后,才能挂起当前线程
ReentrantLock 的 unlock 方法源码
public void unlock() { sync.release(1); }
public final boolean release(int arg) { // 核心释放锁方法 if (tryRelease(arg)) { Node h = head; // 如果头节点不为null,并且头节点的状态不为0,唤醒排队的线程 if (h != null && h.waitStatus != 0) // 唤醒线程 unparkSuccessor(h); return true; } return false; }
private void unparkSuccessor(Node node) { // 获取头节点状态 int ws = node.waitStatus; // 如果头节点状态小于0,换为0 if (ws < 0) compareAndSetWaitStatus(node, ws, 0); // 拿到当前节点的next Node s = node.next; // 如果s == null ,或者s的状态为1 if (s == null || s.waitStatus > 0) { // next节点不需要唤醒,需要唤醒next的next s = null; // 从尾部往前找,找到状态正常的节点。(小于等于0代表正常状态) for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } // 经过循环的获取,如果拿到状态正常的节点,并且不为null if (s != null) // 线程唤醒 LockSupport.unpark(s.thread); }
// 核心的释放锁资源方法 protected final boolean tryRelease(int releases) { // state - 1 int c = getState() - releases; // 如果释放锁的线程不是占用锁的线程,抛异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); // 是否成功的将锁资源释放 boolean free = false; if (c == 0) { // 如果state = 0,代表成功释放锁资源 free = true; setExclusiveOwnerThread(null); } // 设置state值 setState(c); return free; }#Java##程序员#
查看14道真题和解析