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. 关于ASPxComboBox通过ClientInstanceName,js获取不到控件的问题

    今天突然遇到一个很奇葩的问题 ASPxComboBox中设置了ClientInstanceName.但是通过cmbOrganization.GetValue()获取不到值. 报错cmbOrganiza ...

  2. DataGridView列标题(列标头)不能居中的解决方法

    winform DataGridView列标题(列标头)不能完全居中的解决方法,一般列标题的居中我们都使用 DgvDemo.ColumnHeadersDefaultCellStyle.Alignmen ...

  3. __int64 与long long 的区别

    //为了和DSP兼容,TSint64和TUint64设置成TSint40和TUint40一样的数 //结果VC中还是认为是32位的,显然不合适 //typedef signed long int    ...

  4. sql语句之from子句

    如何从表中查询一个字端的数据 select  字段名  from  表名: 演示:从s_emp表中把月薪查询出来 select salary from s_emp ; (分号代表结束) 如何从表中查询 ...

  5. 小程序通过用户授权获取手机号之getPhoneNumber

    小程序有一个获取用户很便捷的api,就是通过getPhoneNumber获取用户的已经绑定微信的手机号码.有一点要大家注意,现在微信和注重用户体验,有些方法都是需要用户主动去触发才能调用的,比如get ...

  6. 【代码笔记】iOS-产生随机字符串

    一,代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, ...

  7. page、request、session和application有什么区别?

    转自:http://liuyuru.iteye.com/blog/773367 1.简单说 page指当前页面.在一个jsp页面里有效 2.request 指从http请求到服务器处理结束,返回响应的 ...

  8. bower 和 npm 的区别详细介绍

    摘要: 本文讲的是bower 和 npm 的区别详细介绍, 简单的说,npm是进行后端开发中,使用的模块安装工具,而bower,是前端的模块安装工具. 比如,在安装express,socket.io时 ...

  9. SD从零开始15-18

    SD从零开始15 税(Taxes) 税确定的标准Criteria for tax determination 你可以在sales organization level分配一个rule(blank,A, ...

  10. IIS8发布Asp.net MVC程序后出现404错误,处理程序staticFile

    新部署的虚拟机,运行Asp.net MVC程序,出现如下图错误: 解决方法: 添加功能和角色->添加角色->Web服务器IIS->应用程序开发->Asp.net3.5 /Asp ...