AQS详解

解释

AQS:全称“AbstractQueuedSynchronizer”,直译过来是抽象的队列同步器,一般我们把它叫做AQS,java中大部分并发类都是通过它来实现线程同步。它内部定义了一个变量(volatile int state)和一个等待队列,前者表示加锁状态,后者在多线程情况下争用资源时被阻塞会进入等待队列。

源码解析

volatile int state

volatile 是一个关键字,在并发处理中也经常会用到,后面单独用一篇文章介绍。

(已去除源码中的注释,方便阅读)

private volatile int state;
protected final int getState() {
        return state;
    }
protected final void setState(int newState) {
        state = newState;
    }
protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

独占锁(下面会介绍)state初始为0,表示未锁定状态,A线程加锁成功则state+1,这样后面的线程尝试获取锁的时候就会失败,只有当A线程释放锁state=0时,后面的锁才有可能成功获取锁。如果是可重入锁,那么A线程再次获取锁的时候,state会累加,当然,释放锁也要一层一层释放,直到state=0。共享锁state初始为N,多个线程可以同时执行,每个线程执行完会state-1,直到state=0时,再调用主线程。

其中compareAndSetState方法,是原子操作,里面使用了unsafe中的compareAndSwapInt方法,这个Unsafe(不安全)类,听着就不靠谱,为什么这里会用到呢。其实不止在这里,在JUC(java.util.concurrent)包中,尤其是在CAS里大量的用到Unsafe,这是因为Java不能像c语言那样直接访问操作系统底层,但Unsafe类提供了硬件级别的原子操作,而且有很高的效率。那为什么官方不建议开发者使用这个类呢,感觉特地取个这名字(Unsafe)就是吓唬程序员,不要用。因为Unsafe中直接访问内存的方法中使用的内存不受JVM管理,也就不能被GC,需要手动管理,稍有不慎就可能导致内存泄漏。

队列操作

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

将节点插入队列,必要时进行初始化。

里面的for (;;),又是个骚操作,有人会问为啥不用while(true)呢,都是无限循环,而且while(true)看着就很舒服。经常看源码的同学,可能会发现,jdk源码中很多地方都是for(;;),至于为啥用这个,咱们以后有机会再讨论。

Node t = tail;(tail是尾节点,head是头节点)先定义一个尾部节点,如果尾节点是空的,说明队列是空的,这时就需要初始化,源码中特地加了注释// Must initialize,(这种直接在后面加注释的,咱们最好不要学,不符合阿里代码规范,但是Doug Lea是大大佬,阿里代码规范管不住他);初始化以后,接着循环进入else,node.prev = t;将当前节点挂在尾节点后面;(这种node.prev指向上个节点,t.next指向下个节点,这是双向队列的操作,还有单向队列,有兴趣的可以去了解一下)。

看这一个方法里就出现了compareAndSetHead和compareAndSetTail两个CAS操作,点进去发现还是Unsafe实现的,由此可见这个类在多线程中还是很重要的。

AQS中还有很多方法,咱们不一一介绍了,下面介绍几个和资源共享相关的方法。

资源共享方式

AQS定义了两种资源共享方式

  • 独占资源,只有一个线程能执行,如ReentrantLock
  • 共享资源,多个线程可以同时执行,如Semaphore/CountDownLatch。

独占模式采用tryAcquire-tryRelease实现,共享模式采用tryAcquireShared-tryReleaseShared实现。有一些特殊的锁两种模式都使用,比如ReentrantReadWriteLock(读写锁)。

  • isHeldExclusively():该线程是否独占资源。

    protected boolean isHeldExclusively() {
            throw new UnsupportedOperationException();
        }
  • tryAcquire(int):独占方式。尝试获取资源。

    protected boolean tryAcquire(int arg) {
            throw new UnsupportedOperationException();
        }
  • tryRelease(int):独占方式。尝试释放资源。

    protected boolean tryRelease(int arg) {
            throw new UnsupportedOperationException();
        }
  • tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败; 0 表示成功,但没有剩余
    可用资源;正数表示成功,且有剩余资源。

    protected int tryAcquireShared(int arg) {
            throw new UnsupportedOperationException();
        }
  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回
    true,否则返回 false。

    protected boolean tryReleaseShared(int arg) {
            throw new UnsupportedOperationException();
        }
Image placeholder
老鹰
未设置
  62人点赞

没有讨论,发表一下自己的看法吧

推荐文章
Go语言高级编程_2.6 实战: 封装qsort

2.6实战:封装qsort qsort快速排序函数是C语言的高阶函数,支持用于自定义排序比较函数,可以对任意类型的数组进行排序。本节我们尝试基于C语言的qsort函数封装一个Go语言版本的qsort函

QString之arg

QString的arg接口主要用于字符串组合的功能。arg接口列表QStringarg(constQString&a,intfieldWidth=0,QCharfillChar=QLatin1Char

03.4. Go 的 http 包详解

前面小节介绍了Go怎么样实现了Web工作模式的一个流程,这一小节,我们将详细地解剖一下http包,看它到底是怎样实现整个过程的。 Go的http有两个核心功能:Conn、ServeMux Conn的g

详解 PHP 中的三大经典模式

单例模式 单例模式的含义:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。单例模式的三

详解 PHP 中的三大经典模式

单例模式 单例模式的含义:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。单例模式的三

详解 PHP 反射的基本使用

PHP反射 今天我要给大家讲解的是PHP当中使用非常普遍的高级操作:反射。反射在当今几乎所有的PHP框架或者工具中都占用非常重要的角色,就比如Laravel的容器,容器对于Laravel架构来说极其重

Redis为什么是单线程、及高并发快的3大原因详解

Redis的高并发和快速原因 1.redis是基于内存的,内存的读写速度非常快; 2.redis是单线程的,省去了很多上下文切换线程的时间; 3.redis使用多路复用技术,可以处理并发的连接。非阻塞

Swoft2 配置详解

Swoft2配置详解更多资料请关注swoft系列教程、小白系列教程定期连载基本功能介绍 配置项是只读的,不能动态修改.所以不要尝试着动态修改配置 Swoft2的配置分为两类,环境配置和应用配置。 en

详解 varint 编码原理

什么是Varint编码Varint是一种使用一个或多个字节序列化整数的方法,会把整数编码为变长字节。对于32位整型数据经过Varint编码后需要1~5个字节,小的数字使用1个byte,大的数字使用5个

万字详解Oracle架构、原理、进程,学会世间再无复杂架构

学习是一个循序渐进的过程,从面到点、从宏观到微观,逐步渗透,各个击破,对于Oracle, 怎么样从宏观上来理解呢?先来看一个图,这个图取自于教材,这个图对于从整体上理解ORACLE 的体系结构组件,非

详解 | 阿里怎么做双11全链路压测?

导读:全链路压测是阿里的首创,本文将从工作内容、操作过程、运行总结等多个方向来介绍下阿里内部典型电商活动(如双11准备),以给大家展示一个完整的压测流程,帮助更多的企业和用户更好的完成性能测试。前言关

详解数据服务共享发布

引言:随着云计算、大数据、物联网等技术兴起,数据朝着多样性、高体量、高速度方向发展,如何将海量数据安全、稳定、高效地数据共享出去成为各企业关注的重点。本次微课堂通过普元在数据服务共享平台研发过程中的实

数据库大牛李海翔详解全局读一致性技术

作者简介:李海翔,网名“那海蓝蓝”,腾讯金融云数据库技术专家。中国人民大学信息学院工程硕士企业导师。著有《数据库事务处理的艺术:事务管理和并发访问控制》、《数据库查询优化器的艺术:原理解析与SQL性能

共享内存在不同系统的应用与优劣详解

共享内存是一种使计算机程序能够同时共享内存资源以实现更高性能和更少冗余数据副本的技术。共享系统内存可以在单处理器系统、并行多处理器或集群微处理器上运行。对于分布式系统会有一些差异,但共享内存也可以其上

Oracle数据库不同损坏级别的恢复详解

墨墨导读:在DBA的日常工作中不可避免存在着数据库的损坏,本文将主要介绍Oracle数据库遇到不同损坏级别下的应该采用的恢复方法,供读者在遇到此类情景时,能的找到适合自己的恢复方法,提高工作效率。数据

千字访谈魏松斌 详解思科Wi-Fi 6

自1997年,IEEE提出第一代Wi-Fi协议,到现在已有20余年。期间经历不断完善,由最早的802.11、802.11b、802.11g/a、802.11n,到沿用至今的802.11ac和即将爆发的

挑重点,详解华为最新 “一奖两组”

继开源GaussDB,成立鲲鹏智能数据产业联盟数据库产业推进组等之后,华为围绕数据基础设施,构建数据产业格局和生态方面再爆大动作。11月19日,“以引领数据基础设施,携手迈入智能时代”为主题,由华为主

详解IBM i 操作环境的最新版本IBM i 7.4 和新特许程序 IBM Db2 Mirror for i

一、背景随着行业客户大规模上云的趋势越来越明显,Power在企业云化中将扮演越来越重要的角色。过去一年,浪潮商用机器基于开放的Power技术的服务器,完善服务器的生态系统,建立可持续发展的服务器业务,

YOLO目标检测从V1到V3结构详解

本文主要内容是对YOLO系列进行综述目标检测评价指标IoU(Intersection-over-Union)指标IoU简称交并比,顾名思义数学中交集与并集的比例。假设有两个集合A与B,IoU即等于A与

css中Position属性图文详解

1.介绍1.1说明Position属性:规定元素的定位类型。即元素脱离文档流的布局,在页面的任意位置显示。1.2主要的值①absolute:绝对定位;脱离文档流的布局,遗留下来的空间由后面的元素填充。

vue路由使用图文详解

传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。本文将以示例的形式来介绍vue-router的各个特性,一共包含6个示例

css属性兼容性详解

盒模型属性【宽高width/height】(全兼容)widthheight(IE6-不支持)min-widthmax-widthmin-heightmax-height【内边距padding】padd

css栅格布局图文详解

圣杯布局圣杯布局是一种三列布局,两边定宽,中间自适应:css:*{ box-sizing:border-box; } html,body{ width:100%; height:100%; margi

Vue命令行工具vue-cli详解

本文将详细介绍Vue命令行工具vue-cli。概述Vue-cli是Vue官方提供的用于初始化Vue项目的脚手架工具。使用Vue-cli有以下几大优势1、Vue-cli是一套成熟的vue项目架构设计,会

css优先级详解

样式的优先级多重样式(MultipleStyles):如果外部样式、内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况。一般情况下,优先级如下:(外部样式)Externalstyleshee