• 8、AQS


    AQS(抽象队列同步器)

    1、AQS解决了什么问题

    CAS自旋实现的轻量级锁的两大问题

    1. CAS空自旋浪费大量CPU资源
    2. 导致“总线风暴”(大量的cas操作导致总线流量剧增)

    关于总线风暴以及总线锁的知识,参考http://t.csdn.cn/3wLCD

    解决CAS恶性空自旋有效方式(空间换时间)两种方式

    1. 分散热点,类似LongerAdder、ConcurrentHashMap
    2. 队列削峰(JUC通过AQS实现)

    2、学习AQS之前,了解一下CLH锁(作为AQS的雏形)

    请添加图片描述

    CLH锁的特点:

    • 单向FIFO队列(公平锁)
    • 竞争资源在一个时间点只能被一个线程锁访问(即队列的头部,表示占用锁的节点)
    • 新加入的抢锁线程需要等待,通过CAS插入队列尾部

    3、AQS的内部队列

    请添加图片描述

    AQS的特点:

    • 双向FIFO队列
      • 每个Node封装了线程,分别指向前驱节点和后继节点
    3.1 Node节点(静态内部类)
     static final class Node {
       
          	//表示线程是因为获取共享资源时阻塞,而被添加到队列中的
            static final Node SHARED = new Node();
        	// 表示线程因为获取独占资源时阻塞,而被添加到队列中的。
            static final Node EXCLUSIVE = null;
    		//以下是节点的状态
         	//取消状态 1
            static final int CANCELLED =  1;
    		//节点等待状态 -1:标识后继线程处于等待状态
            static final int SIGNAL    = -1;
    		//节点等待状态 -2:标识当前线程处于条件等待      
            static final int CONDITION = -2;
    		//节点等待状态 -3:标识下一次共享锁的acquireShared操作需要无条件传播     
            static final int PROPAGATE = -3;
         	
         	//节点状态:Canceled Signal Condition Propagate 0
         	//普通同步节点的初始值为0,条件等待节点的初始值为-2
            volatile int waitStatus;
    		//前驱节点,当前节点会在前驱节点上自选,检查前驱节点的waitStatus的状态
            volatile Node prev;
    
            volatile Node next;
    
            volatile Thread thread;
    		//如果当前Node不是普通节点,而是条件等待节点,则节点处与某个条件的等待队列上
         	//此属性指向下一个条件等待节点
            Node nextWaiter;
    

    waitStatus属性:

    1. Canceled:标识该线程节点已释放(超时、中断),已取消的节点不会被阻塞,需要从等待队列中取消等待
    2. Signal:表示其后继节点处于等待状态,如果当前节点被取消或释放,会通知其后继节点
    3. Condition:
    4. Propagate:waitStatus为-3时,表示该下个线程获取共享锁,自己的共享状态会被无条件的传播下去,因为共享锁可能出现同时有N个锁可以用
    3.2 AQS的核心成员
    //队头节点	
    private transient volatile Node head;
    //队尾节点
    private transient volatile Node tail;
    //标记为状态,AQS适用state标识锁的状态  
    private volatile int state;
    //设置同步状态(无法保证原子性)
    protected final void setState(int newState) {
       
            state = newState;
        }
    //通过同步状态(通过CAS保证原子性)    
    protected final boolean compareAndSetState(int expect, int update) {
       
            // See below for intrinsics setup to support this
            return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
        }
    
    关于ReentrantLock可重入特性

    ​ ReentrantLock初始化state为0,表示未锁定状态。线程A调用tryAcquire()独占该锁并使其state+1.其他线程对该锁tryAcquire()会失败。直到A线程unlock该锁的state为0(释放锁)。A线程在此过程中,可以重复获取该锁(state累加),累加多少次,就要释放多少次。

    3.3 AbstractOwnableSynchronizer(查看占用该锁(独占锁的情形下生效)的线程)

    AQS继承了AbstractOwnableSynchronizer

    请添加图片描述

    public abstract class AbstractOwnableSynchronizer
        implements java.io.Serializable {
       
    
        /** Use serial ID even though all fields transient. */
        private static final long serialVersionUID = 3737899427754241961L;
    
        /**
         * Empty constructor for use by subclasses.
         */
        protected AbstractOwnableSynchronizer() {
        }
    
        /**
         * The current owner of exclusive mode synchronization.
         独占锁情形下,占用该锁的线程
         */
        private 
  • 相关阅读:
    中石化、中石油接口文档源码分享
    基于Java的城市天然气费管理系统的设计与实现(源码+lw+部署文档+讲解等)
    【图像融合】基于DSIFT多聚焦图像融合附matlab代码
    Radash库使用说明——数组方法篇(全)
    Python - GFPGAN + MoviePy 提高人物视频画质
    五年了,我在 CSDN 的两个一百万。
    Linux中make命令和makefile文件的编写,最后附完整代码。
    【Node】Node实现网络编程
    基于安卓android微信小程序的校园维修平台
    在宇宙的眼眸下,如何正确地关心东数西算?
  • 原文地址:https://blog.csdn.net/zhangshuai66/article/details/127103181