AQS总结
前言
AQS(Abstract Queued Synchronizer)是JUC并发包中的核心基础组件,作者是大名鼎鼎的Doug Lea。通过AQS可以实现大部分的同步需求。
宏观架构
AQS包括一个state和一个FIFO的CLH队列,如下图所示:
CLH队列中的每个节点Node就可以对应与争用该资源的线程,Node的数据结构如下所示:
1 |
static final class {
static final Node SHARED = new Node();
|
lock()代码如下:
1 |
final void lock() {
|
如果当前的state值为0,当前线程获得lock,将state的值通过cas的方式设置为1。如果不是0,则添加到队列中。通过acquire方法去申请资源。
1 |
public final void acquire(int arg) {
|
tryAcquire:
1 |
final boolean nonfairTryAcquire(int acquires) {
|
再次获取锁尝试失败后,调用addWaiter将线程封装成节点信息,加入到等待队列中。
1 |
private Node addWaiter(Node mode) {
|
addWaiter首先会通过cas的方式快速的去添加到队列的尾部,如果添加不成功,调enq(node)再次入队;enq(node)是一个死循环,不断的通过cas去添加到节点,直到成功。
1 |
private Node enq(final Node node) {
|
线程节点进入队列后,调用acquireQueued,acquireQueuedxiang
1 |
final boolean acquireQueued(final Node node, int arg) {
|
最关键的应该是shouldParkAfterFailedAcquire方法,如果每个线程都在这么自旋的去拿锁,cpu肯定炸了。所以,当当前的前一个节点处于SIGNAL状态的时候,可以挂起当前线程。这个操作就好比在排队的时候和前一个人说:我出去买点吃的,你轮到的时候叫我一下。当前面的节点轮到的时候,会唤醒当前线程,然后又开始自旋,判断自己能否拿到同步状态,如果拿到,就获取到了锁,这就是一个完整的获得同步状态的过程。
至于如何挂起当前线程,使用的是LockSupport的park()挂起当前线程。park可以精确的进行挂起,精确到thread。
释放锁的过程
1 |
reentrantLock.lock(); //释放锁 |
释放的过程正好相反,通过release来释放锁。
1 |
public final boolean release(int arg) {
|
tryRelease的内容主要是:获取state的值,减去要释放的值,如果state已经是0,把当前的线程设置为null。要注意的是,这里完全没有使用cas,因为当前线程还持有锁,绝对的线程安全。
1 |
protected final boolean tryRelease(int releases) {
|
最为关键的 unparkSuccessor(h),这个时候头节点已经处于了获取同步的状态,通过unparkSuccessor(h)来唤醒头节点的后一个节点。从而后一个节点就可以自旋的去获取同步状态。
1 |
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
|
总结
个人认为AQS在很多地方使用cas和自旋的方式,一定程度上提升吞吐率,之前看到过测试ReentrantLock的吞吐比synchronized要高很多,不对synchronized一直在优化,估计现在性能也差不多了,以后做个测试。本文只是总结了AQS的独占式的获取同步状态,还有共享式的获取同步状态,还支持很多的特性,将在后面进行总结。
AQS总结的更多相关文章
- 【Java并发编程实战】----- AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...
- 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport
在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...
- 【Java并发编程实战】----- AQS(二):获取锁、释放锁
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...
- 【Java并发编程实战】----- AQS(一):简介
在前面博客中,LZ讲到了ReentrantLock.ReentrantReadWriteLock.Semaphore.CountDownLatch,他们都有各自获取锁的方法,同时相对于Java的内置锁 ...
- 获取文件的缩略图Thumbnail和通过 AQS - Advanced Query Syntax 搜索本地文件
演示如何获取文件的缩略图 FileSystem/ThumbnailAccess.xaml <Page x:Class="XamlDemo.FileSystem.ThumbnailAcc ...
- 基于ReentrantLock的AQS的源码分析(独占、非中断、不超时部分)
刚刚看完了并发实践这本书,算是理论具备了,看到了AQS的介绍,再看看源码,发现要想把并发理解透还是很难得,花了几个小时细分析了一下把可能出现的场景尽可能的往代码中去套,还是有些收获,但是真的很费脑,还 ...
- 基于AQS的锁
锁分为独占锁和共享锁,它们的主要实现都是依靠AbstractQueuedSynchronizer,这个类只提供一系列公共的方法,让子类来调用.基于我了解不深,从这个类的属性,方法,和独占锁的获取方式去 ...
- Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析
经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...
- Java并发包源码学习之AQS框架(三)LockSupport和interrupt
接着上一篇文章今天我们来介绍下LockSupport和Java中线程的中断(interrupt). 其实除了LockSupport,Java之初就有Object对象的wait和notify方法可以实现 ...
- Java并发包源码学习之AQS框架(二)CLH lock queue和自旋锁
上一篇文章提到AQS是基于CLH lock queue,那么什么是CLH lock queue,说复杂很复杂说简单也简单, 所谓大道至简: CLH lock queue其实就是一个FIFO的队列,队列 ...
随机推荐
- GetTextExtentPoint32
/////////////////////////////////////////////////////////////// // 04FirstWindow.cpp文件 #include < ...
- apt GPG error
W: GPG error: http://extras.ubuntu.com trusty Release: The following signatures couldn't be verified ...
- TPO1-3Timberline Vegetation on Mountains
At the upper timberline the trees begin to become twisted and deformed. This is particularly true fo ...
- Opencv笔记(十)——卷积基础
卷积 什么是二维卷积呢?看下面一张图就一目了然: 卷积就是循环对图像跟一个核逐个元素相乘再求和得到另外一副图像的操作,比如结果图中第一个元素5是怎么算的呢?原图中3×3的区域与3×3的 ...
- [GX/GZOI2019]旧词(树上差分+树剖+线段树)
考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后 ...
- jmeter接口自动化测试,数据驱动玩法
总体思路:excel管理测试数据,判断不同的接口请求方法,取登陆token值为全局变量方便后面接口调用,预期结果断言: 1.设置获取excel数据源: 2.设置取token以及设置为全局变量: 3.i ...
- Windows环境搭建 face_recognition,dlib
文章参考:https://blog.csdn.net/hongbin_xu/article/details/76284134 文章参考:https://blog.csdn.net/weixin_404 ...
- 成为一名PHP专家其实并不难
本文作者Bruno Skvorc是一名资深的Web开发者.在这篇文章里主要是讲述成为一名专业的PHP专家所要经历的过程,以及在这个过程里要如何学习掌握技巧和对工具的舍取.(以下为编译内容) 当阅读各种 ...
- jQ给下拉框绑定事件,为什么要绑定在框(select标签)上,而不是绑定在选项(option标签)上
这是我在学习锋利的 jquery 书中 5.1.4 的代码时遇到的一个小问题,源代码如下: <head> <style type="text/css"> * ...
- python、anaconda、jupyter notebook、pycharm、spyder
说明: 1.anaconda把任何东西都当做包来管理. 2.anaconda本省集成了python和conda.spyder.numpy等. 3.pip只用于python,conda可用于多种语言. ...