1. 背景

最近团队内部技术分享,我做了个关于AQS的分享。ppt中涵盖的部分要点内容,现在整理到博客上。
关于AQS本身的源码解读,可以参考我之前的博文

2. 要点梳理

下面是一些技术分享的要点梳理。

2.1 LockSupport的实现

AQS中的阻塞/唤醒最终是基于LockSupport的park/unpark实现的。那么park和unpark又是怎么实现的呢?


对于Mac OS,我们主要调试os_bsd.cpp,以上截图取自os_bsd.cpp

我们通过调试JVM可以看到LockSupport中调用的UNSAFE#park最终会通过调用pthread_cond_wait实现阻塞。
而唤醒是通过pthread_cond_signal实现的。

在JVM中每个线程有个自己的Parker类,对一个线程进行阻塞/唤醒操作需要获取到线程Parker对应的互斥锁,Parker内部有个计数器,取值为0和1,调用unpark会置计数器为1.

因此在Java程序中,如果先unpark线程A,再park线程A,线程不会阻塞;但是如果unpark两次,再park两次,线程会阻塞。

2.2 Lock语义实现

java.util.concurrent.locks.lock接口写清了锁的实现必须保证的内存语义。

我们举一个例子:

以上代码截图自java.util.concurrent.ArrayBlockingQueue

JUC中的ArrayBlockingQueue是基于单锁保护的阻塞队列,其中一些关键的共享变量并没有使用volatile关键字,原因是ArrayBlockingQueue的操作使用了同一把ReentrantLock来保护,因为Lock的内存语义保证,ArrayBlockingQueue中的这些共享变量不需要使用volatile保证可见性

那么就ReentrantLock为例,它是如何实现的呢?我们知道ReentrantLock内部组合了一个Sync类,Sync类继承了AQS,ReentrantLock将Lock本身的API委托给Sync(子类)处理。

其奥秘就是AQS中的state变量,它被volatile修饰。

AQS#setState: 具有volatile写语义,AQS#getState: 具有volatile读语义,而AQS#compareAndSetState: 具有volatile读与写语义。

我们以非公平锁ReentrantLock#NonfairSync为例:

这是lock方法的实现,我们可以看到
如果线程通过CAS state进入临界区,那么在进入临界区前的一步操作便是一个具有volatile读写语义的操作。

如上展示的是另一种获取独占锁进入临界区的路径。

可以看到仍然是一个具有volatile读写语义的操作。

那么以释放锁为例:

在出临界区的过程中使用了setState,这是一个volatile写语义的操作。

我们可以看到整个独占锁的获取和释放都被一对volatile读和volatile写语义的操作包着


根据happens-before传递性,线程A释放锁,线程B获得锁后,线程A所有可见的共享变量,对于线程B都可见。

可以说ReentrantLock对Lock内存语义的实现便是基于对AQS的volatile state的操作

2.3 共享锁中PROPAGATE状态的意义

市面上的书籍或者网上的资料基本都对节点的PROPAGATE状态的意义简略带过。
而实际上在AQS中共享模式下的唤醒,仅仅依赖tryAcquireShared返回的int值是不够的,此状态拓展了释放后继线程的条件,保证共享模式下线程唤醒行为传播下去。
可以翻翻Doug Lea网站上当时的代码提交记录,可以看到此状态的引入是为了修复一个在共享锁并发释放情况下潜在的线程hang住问题。此问题更多的细节,可以参考我之前的博文

2.4 一些重要的断言

  • head节点绝对不会是CANCELLED
  • 一个节点的前驱为head,不代表锁正被占用,而是代表当前节点有可能可以成功获取到锁
  • 一个节点的后继为null,不代表这个节点就是tail
  • tryRelease的语义是在完全释放独占锁时才返回true

2.5 如何调试AQS

想不明白的地方想改代码调试,怎么办?
拷出来改,然后再拷个ReentrantLock、Semaphore啥的调调吧
注意Unsafe这个东西用户代码直接拿实例会出SecurityException,需要改一下拷出来的AQS代码,用反射拿Unsafe。

2.6 如何琢磨AQS

  • 琢磨并发程序设计需要有一定时空想象力,把自己大脑当成一个线程调度器吧。
  • Doug Lea老爷子的网站上宝贝很多
  • 网上文章质量参差不齐,关键要有自己理解

技术分享之AQS——内容提要的更多相关文章

  1. 技术分享 | MySQL数据误删除的总结

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 内容提要 用delete语句 使用drop.truncate删除表以及drop删 ...

  2. fir.im Weekly - 新开发时代,需要什么样的技术分享

    "2016年,当我们迎来了如Xcode 8.Swift 3.SiriKit.Android N.Android Instant Apps.React Native等诸多移动开发技术.开发工具 ...

  3. CDN技术分享

    CDN技术分享目录 网络应用服务发展 CDN技术 1.CDN是什么?为什么我们需要它?(简介) 2.CDN能做什么?(作用) 3.CDN是如何工作?(原理) 4.CDN有那些具体应用?(应用) 我们项 ...

  4. HTML5学堂 全新的HTML5/前端技术分享平台

    HTML5学堂 全新的HTML5/前端技术分享平台 HTML5学堂是做什么的? HTML5学堂~http://www.h5course.com~由多名热爱H5的讲师们组成的一个组织.致力于构建一个前端 ...

  5. 内部技术分享的 PPT

    本文的基础是搞了一次内部的技术分享,在此也分享一下本次的PPT的一些内容.先列一下大概内容吧. EF-Code First API(WCF.WebAPI) Xaml MVVM AOP Xamarin. ...

  6. iOS开发技术分享(1)— iOS本地数据存储

    iOS开发技术分享(1)— iOS本地数据存储 前言: 我本是一名asp.net程序员,后来加入了iOS游戏开发队伍,到现在也有一年多的时间了.这一年来,每天都干到2.3点钟才睡觉,不为别的,只为了学 ...

  7. fir.im Weekly - 8 个不能错过的 iOS / Android 技术分享

    本期 fir.im Weekly 收集了 2 月下旬新鲜出炉的 iOS /Android 技术分享.源码等,iOS 中图片技术的解压缩.逆向实战.iOS SDK 实践,Android架构思考.Andr ...

  8. 【技术分享】手把手教你使用PowerShell内置的端口扫描器

    [技术分享]手把手教你使用PowerShell内置的端口扫描器 引言 想做端口扫描,NMAP是理想的选择,但是有时候NMAP并不可用.有的时候仅仅是想看一下某个端口是否开放.在这些情况下,PowerS ...

  9. UWP 手绘视频创作工具技术分享系列 - SVG 的解析和绘制

    本篇作为技术分享系列的第一篇,详细讲一下 SVG 的解析和绘制,这部分功能的研究和最终实现由团队的 @黄超超 同学负责,感谢提供技术文档和支持. 首先我们来看一下 SVG 的文件结构和组成 SVG ( ...

随机推荐

  1. [转]SQL - Create XML - How to set Unicode UTF-8

    本文转自:https://stackoverflow.com/questions/44754356/sql-create-xml-how-to-set-unicode-utf-8 I found a ...

  2. DataSet & DataTable &DataRow 深入浅出

    本篇文章适合有一定的基础的人去查看 ,最好学习过一定net 编程基础在来查看此文章. 1.概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖 ...

  3. CSS学习笔记01 CSS简介

    1.CSS定义 CSS 指层叠样式表 (Cascading Style Sheets),是一种样式表语言,用来描述 HTML 或 XML(包括如 SVG.XHTML 之类的 XML 分支语言)文档的呈 ...

  4. 【Linux】rpm常用命令及rpm参数介绍

    RPM是RedhatPackageManager的缩写,是由RedHat公司开发的软件包安装和管理程序,同Windows平台上的Uninstaller比较类似.使用RPM,用户可以自行安装和管理Lin ...

  5. Spring全家桶系列–SpringBoot渐入佳境

    //本文作者:cuifuan //本文将收录到菜单栏:<Spring全家桶>专栏中 首发地址:https://www.javazhiyin.com/20913.html 萌新:小哥,我在实 ...

  6. pycharm虚拟环境

    pycharm虚拟环境 1. 选择一个本地的空目录,---该目录就作为python虚拟环境目录, 2. 选择本地python安装目录: 3. 勾选该选项后则可以使用base interpreter中的 ...

  7. Vue: ES6常用语法

    ES6 模板字符串:  ~ ${变量名}~ <div id="app"></div> <script> /* 找到对应id */ let ite ...

  8. JavaScript--DOM元素尺寸和位置(22)

    一 获取元素的CSS大小 1.通过style内联获取元素的大小 var box = document.getElementById('box'); // 获得元素; box.style.width; ...

  9. 手机网页meta,添加使其兼容各种浏览器

    虽然手机不像电脑那样会有各种低版本的浏览器,但写手机端网页也是需要注意的: <!-- 优先使用 IE 最新版本和 Chrome --> <meta http-equiv=" ...

  10. wagon-maven-plugin实现自动打包部署到服务器

    1.在maven中添加依赖 <!-- https://mvnrepository.com/artifact/org.codehaus.mojo/wagon-maven-plugin --> ...