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. MyBatis空where拦截器

    最近项目中出现了至少两次因为Mybatis的动态where条件不满足导致实际sql语句的where条件为空,进而查询全表,当数据量比较大的时候,导致OOM的情况. 如何禁止这种情况,个人觉得三种措施: ...

  2. Netty 源码剖析之 unSafe.write 方法

    前言 在 Netty 源码剖析之 unSafe.read 方法 一文中,我们研究了 read 方法的实现,这是读取内容到容器,再看看 Netty 是如何将内容从容器输出 Channel 的吧. 1. ...

  3. Docker基础-容器操作

    1.创建容器 1.新建容器 可以使用docker create命令新建一个容器. [root@linux-node1 ~]# docker create -it ubuntu:latest ffc90 ...

  4. Could not load file or assembly ‘ Oracle.ManagedDataAccess.EntityFramework, Version=6.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342’ or one of its dependencies系统找不到指定文件 处理方法

    前些天做EF Model-First测试,开发环境为VS2013,数据库为Oracle 11g.所有东西都装好数据模型已经建立后准备执行“根据模型生成数据库”命令时,出现:Could not load ...

  5. 撩课-Web大前端每天5道面试题-Day30

    1.什么叫优雅降级和渐进增强? 优雅降级: Web站点在所有新式浏览器中都能正常工作, 如果用户使用的是老式浏览器, 则代码会针对旧版本的IE进行降级处理了, 使之在旧式浏览器上以某种形式降级体验却不 ...

  6. mybatis-plus排除非表中字段

    使用 transient 修饰 private transient String noColumn; 使用 static 修饰 private static String noColumn; 使用 T ...

  7. EF CodeFirst(四) 关系

    数据库表之间有一对一  一对多 多对多关系.那同样,CodeFirst也要能分析这些类之间的这些关系. CodeFirst可以自动通过分析类之间的属性导航属性 从而得出类之间的关系,自动确定外键. 一 ...

  8. MySQL设计之三范式的理解

    转自:https://blog.csdn.net/wangqyoho/article/details/52900585 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要 ...

  9. js 四种调用模式和this的关系总结

    更新: 这篇又简单又明了啊喂 首先看这一篇, 很简单很清楚了,http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascri ...

  10. SD从零开始38-40

    [原创]SD从零开始38 创建Billing Document 根据需要BillingBilling On Request 你可以通过手工输入凭证的号码(订单号码和Delivery note,依赖于你 ...