[db:标题]

摘要:Java并发探索--下篇 承接上文: 博客园【上篇】:https:www.cnblogs.comjackjavacppp18852416 csdn:【上篇】:https:blog.csdn.netokok__TXFarti
Java并发探索--下篇 承接上文: 博客园【上篇】:https://www.cnblogs.com/jackjavacpp/p/18852416 csdn:【上篇】:https://blog.csdn.net/okok__TXF/article/details/147595101 1. AQS实现锁 AQS前传 网址:https://www.cnblogs.com/jackjavacpp/p/18787832 1) aqs分析 AQS 的核心原理是通过一个 int 类型的状态变量 state 来表示同步状态,使用一个 FIFO 队列来管理等待的线程。通过 CAS 操作来保证状态的原子性更新,同时提供了独占模式和共享模式的获取与释放方法。子类可以通过重写 tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared 等方法来实现具体的同步逻辑。 // 关键的属性: // 同步状态,0 表示未锁定,大于 0 表示已锁定[>1表示可重入锁的重入次数] private volatile int state; // 队列的头节点 private transient volatile Node head; // 队列的尾节点 private transient volatile Node tail; // 其中Node的重要变量 //节点已取消: 表示该节点关联的线程已放弃等待(如超时、被中断),需从队列中移除 static final int CANCELLED = 1; //需唤醒后继节点: 当前节点的线程释放锁或取消时,必须唤醒其后继节点。 //节点入队后需确保前驱节点的waitStatus为SIGNAL,否则需调整前驱状态。 static final int SIGNAL = -1; //节点在条件队列中: 表示节点处于条件队列(如Condition的等待队列),而非同步队列(CLH队列)。 //状态转换:当调用Condition.signal()时,节点从条件队列转移到同步队列,状态重置为0 static final int CONDITION = -2; //共享模式下唤醒需传播: 在共享锁(如Semaphore)释放时,确保唤醒动作传播给所有后续节点。 static final int PROPAGATE = -3; //通过状态值控制线程的阻塞、唤醒和队列管理 volatile int waitStatus; aqs独占锁、共享锁的获取和释放分析 独占锁 独占锁的获取: // AbstractQueuedSynchronizer.java public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } tryAcquire:尝试直接获取锁,这是一个需要子类实现的方法, 尝试直接获取锁(如CAS修改state)。【非公平锁:直接尝试CAS抢占资源;公平锁:先检查队列中是否有等待线程(hasQueuedPredecessors()),避免插队】 如果第一步返回false, 则进入第二步: addWaiter:将当前线程封装成一个 Node 节点,并添加到等待队列的尾部。 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 方法插入 enq(node);//enq 方法会通过循环和 CAS 操作确保节点成功插入到队列尾部。
阅读全文