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的队列,队列 ...
随机推荐
- 国产手机早就异军突起,为何还是有很多人“迷恋”iPhone?
近几年,国产手机不论是从外观上还是设计上,以及销量上都比前有了长足的进步,手机的品质和售后也在不断提升.这也让中国手机厂商不断的推出了拥有自己品牌特色的产品.特别是2018年不少国产手机品牌的旗舰级产 ...
- BBS数据库设计
BBS数据库设计 一.BBS数据库设计 # models.py from django.db import models # Create your models here. from django. ...
- BBS注册功能
BBS注册功能 一.后端 1.组件校验数据 """ @author RansySun @create 2019-11-03-11:35 """ ...
- linux下别名的设定
命令别名设定功能: (alias)假如我需要知道这个目录底下的所有文件 (包含隐藏档) 及所有的文件属性,那么我就必须要下达『 ls -al 』这样的指令串,比较麻烦,我们可以为其设定别名为lm al ...
- 指定linux 下默认python版本
sudo rm -rf python sudo ln -s /usr/bin/python3 /usr/bin/python
- Vue环境搭建-项目的创建-启动生命周期-组件的封装及应用
vue项目环境的搭建 """ node >>> python:node是用c++编写用来运行js代码的 npm(cnpm) >>> p ...
- 从git上拉取项目 如果数据库密码不一致 会报错 500
解决方法 在该路径下设置 数据库的密码
- Python_运维中常用的20个库和模块
1.psutil是一个跨平台库(https://github.com/giampaolo/psutil)能够实现获取系统运行的进程和系统利用率(内存,CPU,磁盘,网络等),主要用于系统监控,分析和系 ...
- 吴裕雄--天生自然python学习笔记:python 用pyInstaller模块打包文件
要想在没有安装 Python 集成环境的电脑上运行开发的 Python 程序,必须把 Python 文件打包成 .exe 格式的可执行 文件. Python 的打包工作 PyInstaller 提供了 ...
- rest framework-序列化-长期维护
############### 表结构 ############### from django.db import models class Book(models.Model): titl ...