本文用于记录在学习AQS时,以ReentrantLock为切入点,深入源码分析ReentrantLock的加锁和解锁过程。

同步器AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态(通常锁或者同步组件内部会实现一个Sync类(该类是一个静态内部类),然后让Sync类去继承AQS类,通过继承AQS队列同步器并实现它的抽象方法来管理同步状态),对同步状态进行更改需要使用同步器提供的3个方法 getStatesetStatecompareAndSetState ,它们保证状态改变是安全的。

下图是ReentrantLock中所有的内部类和方法:

3个内部类之间的关系如下图所示:

以ReentrantLock为例,从源码分析如何进行加锁和解锁。

ReentrantLock lc = new ReentrantLock();
lc.lock();
lc.unlock();

(1)ReentrantLock构造函数(为了方便分析,我们以非公平队列为例子)

(2)lc.lock()

ReentrantLock类中的lock()方法调用sync实例中的lock()方法,因为我们是以非公平队列为例子,所以此时的sync实例的类型为NonfairSync。即调用NonfairSync.lock()

紧接着进入209行对应的acquire(1)方法:该方法位于AQS框架中,且被final修饰,即不能被子类重写。

紧接着进入tryAcquire(int arg)方法

我们发现AQS中的tryAcquire(int arg)方法中没有实现体,说明tryAcquire(int arg)方法需要AQS子类实现,根据上面的继承图可知,Sync以及NonfairSync都是AQS的子类,由下图可知,tryAcquire(int arg)方法的实现位于NonfairSync内部类中

进入NonfairSync内部类中的ryAcquire(int arg)方法可以发现其调用了Sync静态内部类中的nonfairTryAcquire方法。


至此成功获取了锁。

(1) 通过ReentrantLock的加锁方法Lock进行加锁操作。
(2) 会调用到内部类Sync的Lock方法,根据ReentrantLock初始化选择的公平锁和非公平锁,执行相关内部类的Lock方法,本质上都会执行AQS的acquire方法。
(3) AQS的Acquire方法会执行tryAcquire方法,但是由于tryAcquire需要自定义同步器实现,因此执行了ReentrantLock中的tryAcquire方法,由于ReentrantLock是通过公平锁和非公平锁内部类实现的tryAcquire方法,因此会根据锁类型不同,执行不同的tryAcquire。
(4) tryAcquire是获取锁逻辑,获取失败后,会执行框架AQS的后续逻辑,跟ReentrantLock自定义同步器无关。

(3)lc.unlock()

释放锁的过程和加锁过程类似,不走进源码,直接上文字版流程

(1) 通过ReentrantLock的解锁方法Unlock进行解锁。
(2) Unlock会调用内部类Sync的release方法,该方法继承于AQS。
(3) release中会调用tryRelease方法,tryRelease需要自定义同步器实现,tryRelease只在ReentrantLock中的Sync实现,因此可以看出,释放锁的过程,并不区分是否为公平锁。
(4) 释放成功后,所有处理由AQS框架完成,与自定义同步器无关。

经过上述的学习,可以归纳总结出如果要自定义一个同步组件,可以按照如下步骤

  • 第一步:内部写一个Sync类继承AbstractQueuedSynchronizer接口。
  • 第二步:根据是否独占来重写队列同步器中的方法,如果需要独占则实现tryAcquire()/tryRelease()等方法,如果不需要独占,则实现tryAcquireShared(int acquires)和tryReleaseShared(int releases)等方法。
  • 第三步:初始化Sync对象,并在锁的获取/释放方法(通常为lock()以及unlock()方法)中调用AQS的acquire()/release()或者acquireShared()/releaseShared()方法。

从ReentrantLock加锁解锁角度分析AQS的更多相关文章

  1. 透过 ReentrantLock 分析 AQS 的实现原理

    对于 Java 开发者来说,都会碰到多线程访问公共资源的情况,这时候,往往都是通过加锁来保证访问资源结果的正确性.在 java 中通常采用下面两种方式来解决加锁得问题: synchronized 关键 ...

  2. java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析

    java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...

  3. 从开发者的角度分析iOS应如何省电

    从开发者的角度分析iOS应如何省电 说明 网上关于iPhone如何省电的文章很多.但是基本没有讲原理.而在生活中,很多人在使用iPhone中有着明显的错误的省电习惯. 本文从iOS开发者的角度,对iO ...

  4. 进程间通信(IPC)+进程加锁解锁

    [0]README 0.1) source code and text description are from orange's implemention of a os: 0.2) for com ...

  5. 源码角度分析-newFixedThreadPool线程池导致的内存飙升问题

    前言 使用无界队列的线程池会导致内存飙升吗?面试官经常会问这个问题,本文将基于源码,去分析newFixedThreadPool线程池导致的内存飙升问题,希望能加深大家的理解. (想自学习编程的小伙伴请 ...

  6. Linux 进程与线程四(加锁--解锁)

    线程共享进程的内存空间,打开的文件描述符,全局变量. 当有多个线程同事访问一块内存空间或者一个变量.一个文件描述符,如果不加控制,那么可能会出现意想不到的结果. 原子操作 对于我们的高级语言(C语言, ...

  7. Android IOS WebRTC 音视频开发总结(六六)-- 三个角度分析美女视频直播这个行业

    本文主要从用户,公司和技术角度分析美女视频直播这个行业,文章最早发表在我们的微信公众号上,支持原创,详见这里, 欢迎关注微信公众号blackerteam,更多详见www.rtc.help 美女视频直播 ...

  8. 从源码的角度分析ViewGruop的事件分发

    从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...

  9. 从不同的角度分析Flex的优缺点

    从不同的角度分析Flex的优缺点 技术角度: (1)具备了RIA时代富客户端的优点(C/S+B/S) (2)支持多种服务器语言(JAVA..NET.PHP)及主流框架(Spring.Hibernate ...

随机推荐

  1. 使用SSM框架实现图片的上传

    SSM实现图片上传功能 效果 在前端页面点击上传图片功能按钮,即弹出文件管理器,选择图片并上传: 思路 在前端页面添加 input 标签,type选择file. 在后端controller编写方法. ...

  2. 树形DP 学习笔记

    树形DP学习笔记 ps: 本文内容与蓝书一致 树的重心 概念: 一颗树中的一个节点其最大子树的节点树最小 解法:对与每个节点求他儿子的\(size\) ,上方子树的节点个数为\(n-size_u\) ...

  3. 012 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 06 浮点型“字面值”

    012 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 06 浮点型"字面值" 浮点型字面值 首先要知道一点:在整型部分中,默认情况下,即整型数 ...

  4. sublime text3配置Python2、Python3的编译环境

    由于Python2.Python3使用量都很高,Python3虽然是未来趋势,但是目前个别库还是只支持Python2.所以,很多人会选择在电脑上安装两个版本的Python,那么使用sublime执行代 ...

  5. 九、Python+Selenium模拟登录

    研究QQ登录规则的话,得分析大量Javascript的加密解密,比较耗时间.自己也是练习很少,短时间成功不了.所以走了个捷径. Selenium是一个WEB自动化测试工具,它运行时会直接实例化出一个浏 ...

  6. 从零开始针对 .NET 应用的 DevOps 运营实践 - 运行环境搭建

    一.Overview 最近的一段时间,在公司里我都在进行基于 Jenkins 和 SonarQube 配合已有的 Gitlab 搭建部门的持续集成环境的工作,虽然之前有使用过 GitHub Actio ...

  7. Hadoop理论基础

    Hadoop是 Apache 旗下的一个用 java 语言实现开源软件框架,是一个开发和运行处理大规模数据的软件平台.允许使用简单的编程模型在大量计算机集群上对大型数据集进行分布式处理.   特性:扩 ...

  8. docker的run操作

    docker的run到底做了什么操作呢? 它会优先寻找本地的镜像,如果没有就到仓库找,找不到返回错误,查找不到该镜像.能找到就拉这镜像下来,以该镜像为模板生产容器实例运行. 备注:图不是自己画的,截图 ...

  9. dockerfile关键字

    DockerFile关键字(保留字指令) FORM:基础镜像,表明当前镜像是基于那么镜像的 MAINTAINER :镜像维护者的名字和邮箱地址 RUN:容器构建时需要用到的命令 EXPOSE:当前容器 ...

  10. 实验 4:Open vSwitch 实验——Mininet 中使用 OVS 命令

    一.实验目的 Mininet 安装之后,会连带安装 Open vSwitch,可以直接通过 Python 脚本调用Open vSwitch 命令,从而直接控制 Open vSwitch,通过实验了解调 ...