UC锁 锁核心类AQS详解

本文详细介绍了Java并发库中的核心组件AQS(AbstractQueuedSynchronizer),包括其核心思想、底层数据结构CLH队列,以及关键方法如acquire、release的工作原理。AQS是构建锁和同步器的基础,如ReentrantLock、Semaphore等高级同步工具都依赖于它。
摘要由CSDN通过智能技术生成

JUC锁: 锁核心类AQS详解

前几天已经总结过AQS的相关知识点。但是总感觉学的不够扎实,今天根据网上的blog在此进行总结。

什么是AQS、为什么它是核心?

AQS是用来构造锁和同步器的框架,中文队列同步器。在java中有很多的同步器都是由AQS作为基础核心的。比如:ReentrantLock、Semaphore等等。程序员也可以自己利用AQS定义符合自己需求的同步器。

AQS的和核心思想?底层数据结构是什么?

核心思想:

**宏观:**AQS的核心思想是,如果一个线程正在请求一个空闲的共享资源,那么AQS则将当前线程设置为有效地工作线程,并且将共享资源设置为锁定状态。当线程请求的共享资源呈现锁定状态,这说明此资源正在被其他线程使用,那么AQS提供了基于CLH虚拟双端队列的线程等待和唤醒操作,即将暂时获取不到锁的线程资源放入队列尾,进行自旋等待。

底层数据结构:

image

这张图是在网上的blog上拿下来的,跟java并发编程艺术这本书上稍稍有些出入,书中并没有提到Condition Queue这个数据结构。Condition queue这是属于Condition的内容。此处进行了结合。

AQS的底层数据结构主要是使用的CLH虚拟双向队列,队列中保存了节点之间的关系。AQS将每条请求共享资源的线程封装成队列的节点结构Node,如果请求锁失败则加入队列的尾部,并实现节点的自旋操作。如果当前节点的前驱结点是首(头)节点,并且其获取锁成功,则此时释放首节点,阻塞其他线程的请求。

上图中的Condition Queue只有在使用了Condition的时候才会存在。

从源码角度分析AQS底层:
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable

AbstractQueuedSynchronizer继承自AbstractOwnableSynchronizer抽象类,并且实现了Serializable接口,可以进行序列化。

AQS源代码中主要包括两个内部类——Node、ConditionObject类

内部类Node
static final class Node {
   
    // 模式,分为共享与独占
    // 共享模式
    static final Node SHARED = new Node();
    // 独占模式
    static final Node EXCLUSIVE = null;        
    // 结点状态
    // CANCELLED,值为1,表示当前的线程被取消
    // SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark
    // CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
    // PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行
    // 值为0,表示当前节点在sync队列中,等待着获取锁
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;        

    // 结点状态
    volatile int waitStatus;        
    // 前驱结点
    volatile Node prev;    
    // 后继结点
    volatile Node next;        
    // 结点所对应的线程
    volatile Thread thread;        
    // 下一个等待者
    Node nextWaiter;
    
    // 结点是否在共享模式下等待
    final boolean isShared() {
   
        return nextWaiter == SHARED;
    }
    
    // 获取前驱结点,若前驱结点为空,抛出异常
    final Node predecessor() throws NullPointerException {
   
        // 保存前驱结点
        Node p = prev; 
        if (p == null) // 前驱结点为空,抛出异常
            throw new NullPointerException();
        else // 前驱结点不为空,返回
            return p;
    }
    
    // 无参构造方法
    Node() {
       // Used to establish initial head or SHARED marker
    }
    
    // 构造方法
        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;
    }
}
内部类ConditionObject类:
// 内部类
public class ConditionObject implements Condition, java.io.Serializable {
   
    // 版本号
    private static final long serialVersionUID = 1173984872572414699L;
    /** First node of condition queue. */
    // condition队列的头结点
    private transient Node firstWaiter;
    /** Last node of condition queue. */
    // condition队列的尾结点
    private transient Node lastWaiter;

    /**
        * Creates a new {@code ConditionObject} instance.
        */
    // 构造方法
    public ConditionObject() {
    }

    // Internal methods

    /**
        * Adds a new waiter to wait queue.
        * @return its new wait node
        */
    // 添加新的waiter到wait队列
    private Node addConditionWaiter() {
   
        // 保存尾结点
        Node t = lastWaiter;
        // If lastWaiter is cancelled, clean out.
        if (t != null && t.waitStatus != Node.CONDITION) {
    // 尾结点不为空,并且尾结点的状态不为CONDITION
            // 清除状态为CONDITION的结点
            unlinkCancelledWaiters(); 
            // 将最后一个结点重新赋值给t
            t = lastWaiter;
        }
        // 新建一个结点
        Node node = new Node(Thread.currentThread(), Node.CONDITION);
        if (t == null) // 尾结点为空
            // 设置condition队列的头结点
            firstWaiter = node;
        else // 尾结点不为空
            // 设置为节点的nextWaiter域为node结点
            t.nextWaiter = node;
        // 更新condition队列的尾结点
        lastWaiter = node;
        return node;
    }

    /**
        * Removes and transfers nodes until hit non-cancelled one or
        * null. Split out from signal in part to encourage compilers
        * to inline the case of no waiters.
        * @param first (non-null) the first node on condition queue
        */
    private void doSignal(Node first) {
   
        // 循环
        do {
   
            if ( (firstWaiter = first.nextWaiter) == null) // 该节点的nextWaiter为空
                // 设置尾结点为空
                lastWaiter = null;
            // 设置first结点的nextWaiter域
            first.nextWaiter = null;
        } while (!transferForSignal(first) &&
                    (first = firstWaiter) != null); // 将结点从condition队列转移到sync队列失败并且condition队列中的头结点不为空,一直循环
    }

    /**
        * Removes and transfers all nodes.
        * @param first (non-null) the first node on condition queue
        */
    private void doSignalAll(Node first) {
   
        // condition队列的头结点尾结点都设置为空
        lastWaiter = firstWaiter = null;
        // 循环
        do {
   
            // 获取first结点的nextWaiter域结点
            Node next = first.nextWaiter;
            // 设置first结点的nextWaiter域为空
            first.nextWaiter = null;
            // 将first结点从condition队列转移到sync队列
            transferForSignal(first);
            // 重新设置first
            first = next;
        } while (first != null);
    }

    /**
        * Unlinks cancelled waiter nodes from condition queue.
        * Called only while holding lock. This is called when
        * cancellation occurred during condition wait, and upon
        * insertion of a new waiter when lastWaiter is seen to have
        * been cancelled. This method is needed to avoid garbage
        * retention in the absence of signals. So even though it may
        * require a full traversal, it comes into play only when
        * timeouts or cancellations occur in the absence of
        * signals. It traverses all nodes rather than stopping at a
        * particular target to unlink all pointers to garbage nodes
        * without requiring many re-traversals during cancellation
        * storms.
        */
    // 从condition队列中清除状态为CANCEL的结点
    private void unlinkCancelledWaiters() {
   
        // 保存condition队列头结点
        Node t = firstWaiter;
        Node trail = null;
        while (t != null) {
    // t不为空
            // 下一个结点
            Node next = t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值