大学网站栏目建设,安徽省建设工程,网站建设助手 西部数码,网站专题页面用什么做AQS资源获取#xff08;独占模式#xff09;
Node节点类
static final class Node {//标记当前节点的线程在共享模式下等待。static final Node SHARED new Node();//标记当前节点的线程在独占模式下等待。static final Node EXCLUSIVE null;//waitStatus的值#xff0c…AQS资源获取独占模式
Node节点类
static final class Node {//标记当前节点的线程在共享模式下等待。static final Node SHARED new Node();//标记当前节点的线程在独占模式下等待。static final Node EXCLUSIVE null;//waitStatus的值表示当前节点的线程已取消等待超时或被中断static final int CANCELLED 1;//waitStatus的值表示后继节点的线程需要被唤醒static final int SIGNAL -1;//waitStatus的值表示当前节点在等待某个条件正处于condition等待队列中static final int CONDITION -2;//waitStatus的值表示在当前有资源可用能够执行后续的acquireShared操作static final int PROPAGATE -3;//等待状态值如上1、-1、-2、-3。volatile int waitStatus;//前趋节点volatile Node prev;//后继节点volatile Node next;//当前线程volatile Thread thread;//等待队列中的后继节点共享模式下值为SHARED常量Node nextWaiter;//判断共享模式的方法final boolean isShared() {return nextWaiter SHARED;}//返回前趋节点没有报NPEfinal Node predecessor() throws NullPointerException {Node p prev;if (p null)throw new NullPointerException();elsereturn p;}//下面是三个构造方法Node() {} // Used to establish initial head or SHARED markeNode(Thread thread, Node mode) { // Used by addWaiterthis.nextWaiter mode;this.thread thread;}Node(Thread thread, int waitStatus) { // Used by Conditionthis.waitStatus waitStatus;this.thread thread;}
}尝试获取资源方法分析 public final void acquire(int arg) {if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}获取失败调用addWaiter将当前线程封装成独占模式的节点添加到AQS队列尾部 // mode 独占模式 共享模式private Node addWaiter(Node mode) {Node node new Node(Thread.currentThread(), mode);// 获取到尾节点Node pred tail;// 尾节点不为空if (pred ! null) {// 新节点跟在尾节点后新节点的前驱指向获取到的尾节点node.prev pred;// 新节点设置为尾节点if (compareAndSetTail(pred, node)) {// 刚刚获取的尾节点的后继节点指向新的节点新节点成为最终尾节点添加到队列尾部pred.next node;return node;}}// 队列没有节点直接加入队列enq(node);return node;}// 入队方法private Node enq(final Node node) {// 自旋for (;;) {// 获取尾节点Node t tail;// 为空队列为空直接队尾为同一个节点入队if (t null) { if (compareAndSetHead(new Node()))tail head;} else {// 不为空新节点的前驱为队列的尾节点node.prev t;// 新节点成为队列尾节点if (compareAndSetTail(t, node)) {// 旧的尾节点的后继是新节点新节点成为队列新的尾节点t.next node;return t;}}}}通过addWaiter已经将当前线程封装成独占模式的 Node 节点并成功放入队列尾部。接下来会调用acquireQueued方法在等待队列中排队
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);}}//将当前节点设置为头节点
private void setHead(Node node) {head node;node.thread null;node.prev null;
}
// 判断当前线程是否可以进入waiting状态
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// 获取前驱节点的等待状态int ws pred.waitStatus;if (ws Node.SIGNAL) // 可以被唤醒return true;if (ws 0) { // 表示当前线程被取消do {// 关键 节点一直往前移动直到找到状态0的节点node.prev pred pred.prev;} while (pred.waitStatus 0);pred.next node;} else {// 下面节点进来的条件前驱节点是SIGNAL这里设置为SIGNALcompareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}// 挂起线程private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();
}protected final boolean tryAcquire(int acquires) {final Thread current Thread.currentThread();// 判断是否0int c getState();if (c 0) {if (!hasQueuedPredecessors() compareAndSetState(0, acquires)) {// 设为当前线程setExclusiveOwnerThread(current);return true;}}// 不为0 尝试获取锁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资源获取独占模式特点
1.互斥访问Mutual Exclusion
单线程持有同一时间只允许一个线程持有资源状态管理通过 state 变量volatile int表示资源状态CAS操作使用 compareAndSetState 确保状态更新原子性示例ReentrantLock 中 state0 表示未锁定state0 表示锁定状态
2. 线程阻塞队列CLH Queue
FIFO队列使用双向链表实现的 CLH 变体队列节点类型Node.EXCLUSIVE 表示独占模式节点排队机制获取资源失败的线程会被封装为节点加入队列尾部
3. 可重入支持Reentrancy
重入计数state 变量记录重入次数持有线程通过 exclusiveOwnerThread 记录当前持有线程示例ReentrantLock 允许线程多次获取同一把锁 AQS资源释放独占模式 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;}// 唤醒后继节点的线程传入节点private void unparkSuccessor(Node node) {// 获取当前节点的等待状态int ws node.waitStatus;if (ws 0)// 0 尝试设置为0node.compareAndSetWaitStatus(ws, 0);// 获取节点后继Node s node.next;// 后继节点为空或等待状态0 节点取消if (s null || s.waitStatus 0) {s null;// 从尾部向前遍历for (Node p tail; p ! node p ! null; p p.prev)if (p.waitStatus 0)s p;}// 不为空准备进行唤醒操作if (s ! null)// 线程停止阻塞LockSupport.unpark(s.thread);}AQS 资源释放独占模式流程图
AQS资源释放独占模式特点
1.状态更新
通过 tryRelease 更新同步状态清除当前持有线程
2.唤醒策略
只唤醒头节点的下一个有效节点采用从后向前查找策略解决并发入队问题
3.线程安全
使用 CAS 更新 waitStatus无锁化设计确保高性能
4.取消处理
自动跳过已取消节点waitStatus 0确保唤醒的节点都是有效等待节点