专业制作网站系统,顺的网站建设报价,怎么做网络推广最有效,出售全国精准客户电话号码目录 AQS简单入门为什么说AQS是JUC包下的重要基石AQS能干嘛#xff1f;实际实现原理AQS自身成员变量Node内部类的成员变量源码解读总结 AQS简单入门
AQS是抽象的队列同步器#xff0c;是用来实现锁或者其它同步器组件的公共基础部分的抽象实现#xff0c;是重量级基础框架及… 目录 AQS简单入门为什么说AQS是JUC包下的重要基石AQS能干嘛实际实现原理AQS自身成员变量Node内部类的成员变量源码解读总结 AQS简单入门
AQS是抽象的队列同步器是用来实现锁或者其它同步器组件的公共基础部分的抽象实现是重量级基础框架及整个JUC体系的基石主要用于解决锁分配给谁的问题
整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作并通过一个int类变量表示持有锁的状态
为什么说AQS是JUC包下的重要基石
和AQS有关的类
ReentrantLockCountDownLatchReentrantReadWriteLockSemaphore… 都继承了AQS类
我们使用锁可能只是简单的lock和unlock但是实际底层锁的实际逻辑还是AQS来去执行的
AQS能干嘛
有堵塞需要排队实现排队的必需队列等候机制管理
如果共享资源被占用就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的将暂时获取不到锁的线程加入到队列中这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的结点对象(Node)通过CAS、自旋以及LockSuppor.park()的方式维护state变量的状态使并发达到同步的效果。
实际实现原理
AQS使用一个volatile的int类型的state成员变量来表示同步状态通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配通过CAS完成对State值的修改。
AQS自身成员变量 下图就是模拟AQS工作的一个流程图 head头指针头部出队 tail尾指针尾部入队 state同步状态判断是否阻塞
Node内部类的成员变量 由于我本地装的是jdk17AQS与jdk8的源码有不一致情况所以直接抠图给大家来看看Node的一些内部成员变量
源码解读总结
以ReentrantLock非公平锁为案例去进行lock和unlock的debug源码解读jdk8情况下
整个ReentrantLock加锁过程分为三个阶段
一、尝试加锁 tryAcquire 方法尝试获取锁以下几种情况会导致获取锁失败: 1、锁已经被其他线程续取; 2、锁没有被其他线程获取但当前线程需要排队: 3、cas 失败(可能过程中已经有其他线程拿到锁了) 锁为自由状态(c0)并不能说明可以立刻执行cas 获取锁因为可能在当前线程获取锁之前已经有其他线程在排队了必须道循先来后到原则获取锁。所以还要调用hasQueuedPredecessors方法查看自己是否需要排队
二、加锁失败线程进入队列这部分逻辑是尝试获取锁失败的情况下当前线程(尝试获取锁的)封装成 Node 对象加入到aqs队列中的处理逻辑 将当前线程封装成 Node对象并加入排队队列中根据排队队列是否执行过初始化执行不同处理逻辑。 1、如果排队队列不为空即之前已经初始化过了此时只需将 新的 node加入排队队列未尾即可。 2、如果排队队列为空需执行队列初始化。enq 会初始化一个 空的 Node作为排队队列 的head然后将需要排队的线程作为head 的 next 节点插入。
三、线程入队列后进入堵塞状态 1、首先判断 node 的前辈节点是不是 head如果是说明它是下一个可以获得锁的线程则调用一次tryAcquire尝试获取锁若获取到则将链表关系重新维护下(node设置为 head之前的 head从链表移出)然后返回。 2、如果 node 的前辈节点不是 head或获取锁失败再判断其前辈节点的 waitState是不是SIGNAL如果是则当前线程调用 park进入阻塞状态如不是: 10则设置为 SIGNAL; 20(1)则表示前辈节点已经被取消了将取消的节点从队列移出重新维护下排队链表关系
然后再次进入 for 循环上面的逻辑重新执行一遍, 就先说到这 \color{#008B8B}{ 就先说到这} 就先说到这 在下 A p o l l o \color{#008B8B}{在下Apollo} 在下Apollo 一个爱分享 J a v a 、生活的小人物 \color{#008B8B}{一个爱分享Java、生活的小人物} 一个爱分享Java、生活的小人物 咱们来日方长有缘江湖再见告辞 \color{#008B8B}{咱们来日方长有缘江湖再见告辞} 咱们来日方长有缘江湖再见告辞