10.AbstractQueuedSynchronizer(AQS)
AbstractQueuedSynchronizer(AQS)
AQS入门理论知识
概念
抽象队列同步器,是用来实现锁或者其它同步器组件的公共基础部分的抽象实现,是重量级基础框架及整个JUC体系的基石,主要用于解决锁分配给"谁"的问题
整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态
双向队列:
* +------+ prev +-----+ +-----+ * head | | <---- | | <---- | | tail * +------+ +-----+ +-----+
官网解释:
Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. 为实现阻塞锁和相关的同步器提供一个框架,依赖于一个先进先出的等待队列
Subclasses can maintain other state fields, but only the atomically updated {@code int} value manipulated using methods {@link #getState}, {@link #setState} and {@link #compareAndSetState} is tracked with respect to synchronization. 依靠单个原子int值来表示状态,通过占用和释放的方法,改变状态值
为什么AQS是JUC内容中最重要的基石
ReentrantLock中的AQS
public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** Synchronizer providing all implementation mechanics */ private final Sync sync; abstract static class Sync extends AbstractQueuedSynchronizer {} } public void lock() { sync.lock(); } public void unlock() { sync.release(1); }
锁和同步器的关系
锁,面向锁的使用者定义了程序员和锁交互的使用层API,隐藏了实现细节,你调用即可。
同步器,面向锁的实现者, Java并发大神DougLee,提出统一规范并简化了锁的实现,将其抽象出来屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的公共基础部分。
作用
加锁会导致阻塞有限塞就需要排队,实现排队必然需要队列
抢到资源的线程直拨使用处理业务,抢不到资源的必然涉及一种排队等候机制。抢占资源失败的线程继续去等待(类似银行业务办理窗口都满了,暂时没有受理窗口的顾客只能去候客区排队等候),但等候线程仍然保留获取锁的可能且获取锁流程仍在继续(候客区的顾客也在等着叫号,轮到了再去受理窗口办理业务)。
既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?
如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的结点对象(Node),通过CAS、自旋以及LockSupport.park()的方式,维护state变量的状态,使并发达到同步的效果。AbstractQueuedSynchronizer源码:
AQS使用一个volatle的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。
static final class Node { static final Node SHARED = new Node(); static final Node EXCLUSIVE = null; static final int CANCELLED = 1; static final int SIGNAL = -1; static final int CONDITION = -2; static final int PROPAGATE = -3; volatile int waitStatus; volatile Thread thread; Node nextWaiter; /** * Returns true if node is waiting in shared mode. */ final boolean isShared() { return nextWaiter == SHARED; } final Node predecessor() throws NullPointerException { Node p = prev; if (p == null) throw new NullPointerException(); else return p; } Node() { } Node(Thread thread, Node mode) { // Used by addWaiter this.nextWaiter = mode; this.thread = thread; } Node(Thread thread, int waitStatus) { // Used by Condition this.waitStatus = waitStatus; this.thread = thread; } } private transient volatile Node head; private transient volatile Node tail; private volatile int state; AQS同步队列基本结构:
AQS源码分析前置知识
AQS体系架构
AQS自身结构
static final class Node { static final Node SHARED = new Node(); static final Node EXCLUSIVE = null; static final int CANCELLED = 1; static final int SIGNAL = -1; static final int CONDITION = -2; static final int PROPAGATE = -3; volatile int waitStatus; volatile Thread thread; Node nextWaiter; /** * Returns true if node is waiting in shared mode. */ final boolean isShared() { return nextWaiter == SHARED; } final Node predecessor() throws NullPointerException { Node p = prev; if (p == null) throw new NullPointerException(); else return p; } Node() { } Node(Thread thread, Node mode) { // Used by addWaiter this.nextWaiter = mode; this.thread = thread; } Node(Thread thread, int waitStatus) { // Used by Condition this.waitStatus = waitStatus; this.thread = thread; } } private transient volatile Node head; private transient volatile Node tail; private volatile int state;
private volatile int state; 变量:
AQS的同步状态State成员变量,0临界资源可用,1临界资源被占用
CLH双向队列:
通过自旋等待,state变量判断是否阻塞,从尾部入队,从头部出队
有阻塞就需要排队,实现排队必然需要队列,实现:state变量+CLH双端队列
内部类Node(AQS内部类)
AQS源码深度分析
Lock接口的实现类,基本都是通过【聚合】了一个【队列同步器】的子英完成线程问控制的
ReentrantLock的原理
private final Sync sync; // 默认是创建非公平锁 public ReentrantLock() { sync = new NonfairSync(); } // true是公平锁,false是非公平锁 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
从最简单的lock方法开始看看公平和非公平
公平锁与非公平锁底层实际都是继承 Sync 这个类 Sync 又继承的AbstractQueuedSynchronizer
从底层看公平锁与非公平锁的区别实现
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); } } ---------------------------------------------------------------------------------- static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }
公平与非公平的底层区别:
lock() 方法:
非公平锁
if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); 先使用cas获取临界区state 如果状态为0则获取锁成功,并将 占有锁设置为当前线程 如果cas失败表示临界区有线程在使用,则请求获得锁acquire 公平锁
final void lock() { acquire(1); } 直接尝试获得锁 acquire(1);方法:是父类AbstractQueuedSynchronizer 定义的方法 有自定义实现
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } tryAcquire方法:是父类AbstractQueuedSynchronizer 定义的方法,但是抛出异常,强制子类实现
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } 非公平锁 NonfairSync:
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; } 公平锁
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } 区别:
公平: if (!hasQueuedPredecessors() && compareAndSetState(0, acquires))
非公平:if (compareAndSetState(0, acquires))
可以明显看出公平锁与非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors()。hasQueuedPredecessors是公平锁加锁时判断等待队列中是否存在有效节点的方法
hasQueuedPredecessors()中判断了是否需要排队,导致公平锁和非公平锁的差异如下:
公平锁:公平锁讲究先来先得,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入等待队列中;
非公平锁:不管是否有等待队列,如果可以获取锁,则立刻占有锁对象。也就是说队列的第一个排队线程苏醒后,不一定就是排头的这个线程获得锁,它还是需要参加竞争锁(存在线程竞争的情况下),后来的线程可能不讲武德插队夺锁了。
以非公平锁ReentrantLock()为例解析AQS底层原理
三大流程走向
1. tryAcquire(arg)
2. addWaiter(Node.EXCLUSIVE)
3. acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
/** * 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. * 以独占模式获取,忽略中断。实现通过调用至少一次{@link #tryAcquire}成功归来。否则,线程可能会排队反复阻塞和解除阻塞,调用{@link#tryAcquire}直到成功。这种方法可以使用实现方法{@link Lock# Lock}。 * @param参数获取参数。该值被传递给{@link #tryAcquire}但未被解释可以代表任何你喜欢的东西。 */ public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
以银行窗口办理为场景说明
AQS属性方法说明
static final class Node { // 线程以共享的方式等待锁 static final Node SHARED = new Node(); // 线程正在以独占得方式使用锁 static final Node EXCLUSIVE = null; // 当前线程获取锁的请求已经取消了 static final int CANCELLED = 1; // 当前线程已经准备好了,就等资源释放锁了 static final int SIGNAL = -1; // 节点在等待队列中,节点线程等待唤醒 static final int CONDITION = -2; // 当前线程处在 SHARED 该字段才会使用 static final int PROPAGATE = -3; // 当前节点在队列中的状态 ---上面的状态都是 waitStatus 的枚举 volatile int waitStatus; // 处于当前节点的线程 volatile Thread thread; // 指向处于下一个 处于CONDITION状态的节点 Node nextWaiter; /** * Returns true if node is waiting in shared mode. */ final boolean isShared() { return nextWaiter == SHARED; } // 返回前驱节点 如果没有抛出npe final Node predecessor() throws NullPointerException { Node p = prev; if (p == null) throw new NullPointerException(); else return p; } Node() { } Node(Thread thread, Node mode) { // Used by addWaiter this.nextWaiter = mode; this.thread = thread; } Node(Thread thread, int waitStatus) { // Used by Condition this.waitStatus = waitStatus; this.thread = thread; } } // CLH队列的头节点 private transient volatile Node head; // CLH队列的尾节点 private transient volatile Node tail; // 临界资源的状态 0空闲,1已被抢占 private volatile int state;
从银行办理业务开始解读源码
A BC三个顾客,去银行办理业务,A先到,此时窗口空无一人,他优先获得办理窗口的机会,办理业务。//A耗时严重,估计长期占有窗口
ReentrantLock reentrantLock = new ReentrantLock();//非公平锁 //A BC三个顾客,去银行办理业务,A先到,此时窗口空无一人,他优先获得办理窗口的机会,办理业务。//A耗时严重,估计长期占有窗口 new Thread(() -> { reentrantLock.lock(); try { System.out.println("----come in A");//暂停20分钟线程 try { TimeUnit.MINUTES.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } finally { reentrantLock.unlock(); } }, "A").start(); //B是第2个顾客,B一看到受理窗口被A占用,只能去候客区等待,进入AQS队列,等待着A办理完成,尝试去抢占受理窗口。 new Thread(() -> { reentrantLock.lock(); try { System.out.println("----come in B"); try { TimeUnit.MINUTES.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } finally { reentrantLock.unlock(); } }, "B").start(); //c是第3个顾客,c一看到受理窗口被A占用,只能去候客区等待,进入AQS队列,等待着A办理完成,尝试去抢占受理窗口,前面是B顾客,FIFO new Thread(() -> { reentrantLock.lock(); try { System.out.println("----come in C"); try { TimeUnit.MINUTES.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } finally { reentrantLock.unlock(); } }, "C").start(); }
- A进来办理
compareAndSetState(0, 1) 成功,将独占线程设置为当前线程
final void lock() { // A进入if块 设置临界资源状态为 1 并且将独占线程设置为当前线程 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
- B进来办理
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); // B进入else块 else acquire(1); }
由于A耗时较长 B进来的时候A还没有结束 进入else块 进入acquire排队
/*进入aquire 首先尝试获得锁*/ public final void acquire(int arg) { // 5 tryAcquire(arg) 为false !tryAcquire(arg)为 true进入 addWaiter(Node.EXCLUSIVE) if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } // 4 尝试获得锁 返回false final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 1 获取临界区状态,因为现在A正在办理,所以 c 为 1 int c = getState(); // 2 临界区状态是不是0 c为1 返回false if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 3 正在办理的线程是不是当前线程,返回false 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; } /*添加到等待队列*/ private Node addWaiter(Node mode) { /*创建队列新节点 mode为 Node.EXCLUSIVE(独占)*/ Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; // 6 由于队列刚开始新建,尾节点为null 不进入if块 if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } // 7入队,只在初始化的时候调用一次 enq(node); return node; } /*第一个节点入队*/ private Node enq(final Node node) { for (;;) { Node t = tail; /*第一次循环*/ if (t == null) { // Must initialize // 8比较并设置为头节点。 unsafe.compareAndSwapObject(this, headOffset, null, update); 将头节点的偏移量设置为新建的节点 new Node()【哨兵节点】 if (compareAndSetHead(new Node())) // 9将头节点赋值给尾节点 /* head ----> +------------+ * | new Node() | * tail ----> +------------+ */ tail = head; } else { /*第二次循环 t != null */ // 10将要存入的节点的前驱节点设置成头节点 node.prev = t; // 11设置尾节点期望尾节点是t,设置成node-->将当前插入的节点设置成尾节点 if (compareAndSetTail(t, node)) { // 12将原来tail的后继节点设置为当前节点 返回尾节点,至此B线程 入队成功 /* head ----> +------------+ <----prev +------------+ * | new Node() | | B线程 | * tail +------------+ next----> +------------+ * | ^ * |_________________________________________________| */ t.next = node; return t; } } } /** * CAS head field. Used only by enq. */ private final boolean compareAndSetHead(Node update) { return unsafe.compareAndSwapObject(this, headOffset, null, update); } /** * CAS tail field. Used only by enq. */ private final boolean compareAndSetTail(Node expect, Node update) { return unsafe.compareAndSwapObject(this, tailOffset, expect, update); }
- 三号线程C进来办理-- addWaiter(node),之前的流程都是相同的
/*添加到等待队列*/ private Node addWaiter(Node mode) { /*创建队列新节点 mode为 Node.EXCLUSIVE(独占)*/ Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; // 1这里将pred = tail,所以pred为B节点,所以不为null if (pred != null) { // 2将C节点的前驱节点设置为B节点 node.prev = pred; // 3设置尾节点指向,cas判断尾节点是否是 pred(B节点),将他设置为当前节点,至此C节点入队成功 /* head ----> +---------+ <-prev +--------+ <-prev +--------+ * | newNode | | B线程 | | C线程 | * tail +---------+ next-> +--------+ next-> +--------+ * | ^ * |----------------------------------------------------------| */ if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } // 不进入 这个方法 enq(node); return node; }
- acquireQueued(final Node node, int arg) 方法 以B为例
/** * Acquires in exclusive uninterruptible mode for thread already in * queue. Used by condition wait methods as well as acquire. * * @param node the node 要入队的Node * @param arg the acquire argument 是1 * @return {@code true} if interrupted while waiting 在等待时被中断则返回true * 自旋获得锁 */ final boolean acquireQueued(final Node node, int arg) { // 是否失败 boolean failed = true; try { // 是否中断 boolean interrupted = false; for (;;) { // 1获取当前节点的第一个节点 B进来就是获取头节点 final Node p = node.predecessor(); // 2B入队时 p == head 为true 继续进行 tryAcquire(1) 返回false if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } // 3将头节点和B节点传入 shouldParkAfterFailedAcquire(p, node) // 10 执行 parkAndCheckInterrupt()-》 LockSupport.park(this); 将当前线程阻塞 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } /** * 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 * *检查并更新获取失败节点的状态。 *如果线程阻塞,返回true。这是主要信号 *控制所有获取循环。要求pred == node.prev。 // 当前线程获取锁的请求已经取消了 static final int CANCELLED = 1; // 当前线程已经准备好了,就等资源释放锁了 static final int SIGNAL = -1; // 节点在等待队列中,节点线程等待唤醒 static final int CONDITION = -2; // 当前线程处在 SHARED 该字段才会使用 static final int PROPAGATE = -3; // 当前节点在队列中的状态 ---上面的状态都是 waitStatus 的枚举 volatile int waitStatus; */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { // 4获取头节点的 waitStatus int ws = pred.waitStatus; // 5刚初始化头节点的waitStatus 默认为 0 进入else // 8 头节点的状态为 SIGNAL 进入方法快 if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ // 9返回true 进入 parkAndCheckInterrupt() 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 { /* * 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. */ // waitStatus必须为0或PROPAGATE。表明我们需要一个信号,但不要立即将线程进行休眠。调用者将需要重试以确保在进入休眠状态之前无法获取所需资源。 // 6将前驱节点的状态设置为 SIGNAL(-1) 表示当前线程已经准备好了,就等资源释放锁了 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } // 7返回false 重新进入 acquireQueued 循环 return false; } /** * CAS waitStatus field of a node. */ private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update); } private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
- 当线程A执行完任务后(unlock)后续线程如何占有锁
// 1 A线程进行unlock() reentrantLock.unlock(); public void unlock() { sync.release(1); } public final boolean release(int arg) { // 2执行 tryRelease(1) if (tryRelease(arg)) { // 8获取头节点 Node h = head; // 9头节点不为null 并且节点的状态为 -1 不为0 if (h != null && h.waitStatus != 0) // 10执行unparkSuccessor unparkSuccessor(h); return true; } return false; } protected final boolean tryRelease(int releases) { // 3 当前线程正在使用资源所以 getState() ==1 并且 releases == 1 所以c == 0 int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 4进入if if (c == 0) { free = true; // 5释放锁占有 setExclusiveOwnerThread(null); } // 6将临界区状态重新设置为 0 setState(c); // 7返回true return free; } protected final void setState(int newState) { state = newState; } 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. */ // 11获取头节点的waitstatus 为 -1 int ws = node.waitStatus; if (ws < 0) // 12将头节点状态 设置为 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. */ // 13获取头节点的后继节点 即 B Node s = node.next; // B的 waitStatus 为-1 不进入if 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; } // 14将 B线程 unpark if (s != null) LockSupport.unpark(s.thread); } final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { // 16 获取B的 前驱节点 即为head final Node p = node.predecessor(); // 17 p == head 为true 并且执行 tryAcquire(arg) 将临界status设置为1 设置独占线程为当前线程并 返回 为true ----> 现在B独占临界资源 // 因为是非公平锁 线程释放锁以后其他线程都有可能获取锁 所以需要进行 tryAcquire(arg) if (p == head && tryAcquire(arg)) { // 18将头节点指针指向 B,并设置 node.thread = null; node.prev = null; setHead(node); // 19将 头节点的next 指针断掉,帮助JVM回收头节点 // 至此哨兵节点(空节点)出队 p.next = null; // help GC failed = false; // 20返回false 流程结束 return interrupted; } // 15 B unpark之后 parkAndCheckInterrupt() 返回false if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } private void setHead(Node node) { head = node; node.thread = null; node.prev = null; } private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
- 如果有(一个/多个)线程在阻塞过程中要出队
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 { // 1线程cancel,需要移除队列 if (failed) cancelAcquire(node); } } private void cancelAcquire(Node node) { if (node == null) return; // 2清除node存放的线程 node.thread = null; // 3跳过已经取消的其他前驱节点,如果有多个都取消,一直找到不是cancel状态的前驱节点,并将当前线程的前驱指向不是cancel状态的前驱节点 Node pred = node.prev; while (pred.waitStatus > 0) node.prev = pred = pred.prev; // 4获取非cancel状态的后继节点 Node predNext = pred.next; // 5将当前node的状态 设置为 CANCELLED node.waitStatus = Node.CANCELLED; // 6如果是最后一个节点,将tail 指向 当前node 的前驱节点,并且将非cancel状态的前驱节点的后继节点设置为当前节点的前驱节点 if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { // 7如果不是最后一个节点 int ws; // 8不是头节点,并且满足出队条件 if (pred != head && ((ws = pred.waitStatus) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && pred.thread != null) { // 9获取要出队节点的下一个节点 Node next = node.next; if (next != null && next.waitStatus <= 0) // 10将非cancel状态的前驱节点的后继节点设置为当前出队节点的后继节点 compareAndSetNext(pred, predNext, next); } else { unparkSuccessor(node); } // 11当前节点的下一个节点指向自己,帮助JVM回收 node.next = node; // help GC } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)