AQS与Synchronized异曲同工的加锁流程

news/2024/5/17 20:21:43 标签: AQS, Synchronized,

在并发多线程的情况下,为了保证数据安全性,一般我们会对数据进行加,通常使用Synchronized或者ReentrantLock同步Synchronized是基于JVM实现,而ReentrantLock是基于Java代码层面实现的,底层是继承的AQS

AQS全称AbstractQueuedSynchronizer,即抽象队列同步器,是一种用来构建和同步器的框架。它维护了一个共享资源state(volatile修饰) + 一个双向链表结构的同步队列 + 一个单链表结构的条件队列,底层利用了CAS机制来保证操作的原子性

AQS通过控制state变量(volatile的int类型)的值来判断的状态,对于不可重入state不是0则阻塞;对于可重入如果state=0则执行抢占,非0则判断当前线程是否是占有的线程,是就把state加1,比如重入5次,那么state加1执行5次,可重入在释放的时候,同样需要释放5次直到state=0其他线程才有资格获得

我们常见的并发ReentrantLock、CountDownLatch、Semaphore、CyclicBarrier都是基于AQS实现的。

仔细研究AQS底层的加原理,其实跟Synchronized的加原理有惊人的相似。

Synchronized_11">Synchronized的加流程

这里直接讨论重量级,忽略升级的过程(对升级过程感兴趣可移步Java对synchronized的实现与优化),重量级底层使用操作系统的互斥来实现。

考虑Synchronized的加流程,Synchronized的对象要能满足以下几个场景:

  1. 多个线程执行到Synchronized代码块,只有一个线程获取,然后执行同步代码块(需要记录哪个线程获取了对象)。
  2. 其他线程被阻塞(被阻塞的线程,是不是可以设计一个阻塞队列)
  3. 持有的线程调用wait方法释放,等待被唤醒(等待的线程,是不是可以设计一个等待队列)
  4. 被阻塞的线程开始竞争
  5. 调用notify方法,唤醒等待的线程,被唤醒的线程进入阻塞队列,一块竞争

上面描述了Synchronized的加流程,Synchronized的对象存储结构如下图所示。

对象的基本工作机制:

  1. 当多个线程同时访问一段同步代码时,首先会进入 _EntryList队列中阻塞
  2. 当某个线程获取到对象的对象后进入临界区域,并把对象中的_owner变量设置为当前线程,即获得对象
  3. 若持有对象的线程调用wait() 方法,将释放当前持有的对象,_owner变量恢复为null,同时该线程进入_WaitSet 集合中等待被唤醒
  4. 在WaitSet集合中的线程被唤醒,会被再次放到EntryList队列中,重新竞争获取
  5. 若当前线程执行完毕也将释放对象并复位变量的值,以便其他线程进入获取

可以发现,Synchronized对象存储结构完美符合最初设想时它需要满足的场景。

AQS_36">AQS的加流程

照例,先分析使用AQS的加需求:

  1. 多个线程执行到acquire方法的时候,只有一个线程获取然后执行同步代码块(需要记录哪个线程获取了对象
  2. 其他线程被阻塞(被阻塞的线程,是不是可以设计一个阻塞队列)
  3. 持有的线程调用await方法,释放,等待被唤醒(等待的线程,是不是可以用设计个等待队列)
  4. 被阻塞的线程开始竞争
  5. 调用signal方法,唤醒等待的线程,被唤醒的线程进入阻塞队列,一块竞争

AQS的加需求跟Synchronized是一样的。AQS实际的加机制是怎么设计的呢?如下图所示。

参考上图,可以发现AQS的加流程并不复杂,只要理解了同步队列和条件队列,以及它们之间的数据流转,就算彻底理解了AQS

  1. 当多个线程竞争AQS时,如果有个线程获取到,就把ower线程设置为自己
  2. 没有竞争到的线程,在同步队列中阻塞(同步队列采用双向链表,CAS尾插)
  3. 持有的线程调用await方法,释放,追加到条件队列的末尾(条件队列采用单链表,尾插)
  4. 持有的线程调用signal方法,唤醒条件队列的头节点,并转移到同步队列的末尾
  5. 同步队列的头节点优先获取到

可以看到AQSSynchronized的加流程几乎是一模一样的,AQS中同步队列就是Synchronized中EntryList,AQS中条件队列就是Synchronized中的waitSet,两个队列之间的数据转移流程也是一样的,阻塞状态的线程被放到同步队列中,等待状态的线程被放到条件队列中,从条件队列唤醒的线程又被转移到同步队列末尾,一块竞争


http://www.niftyadmin.cn/n/82237.html

相关文章

MyBatis 之四(动态SQL之 if、trim、where、set、foreach 标签)

文章目录动态 SQL1. if 标签2. trim 标签3. where 标签4. set 标签5. foreach 标签回顾一下,在上一篇 MyBatis 之三(查询操作 占位符#{} 与 ${}、like查询、resultMap、association、collection)中,学习了针对查询操作的相关知识点…

python+selenium使用webdriver启动chrome出现闪退现象解决

这两天发现之前开发的爬虫程序出问题了:谷歌浏览器出现打开立即闪退的现象,代码未修改过,检查也没有任何问题! 查看chrome浏览器发现版本更新了 ↑(点击chrome浏览器右上角三个点,最下面帮助→Google Chr…

【2022.12.9】Lammps+Python 在计算g6(r)时遇到的问题

目录写在前面绘制g6( r )执行步骤【updated】如何检查图像的正确性:不是编程问题,而是数学问题的一个小bug废稿2则:写在前面 全部log: 【2022.11.16】LammpsPythonMATLAB在绘制维诺图时遇到的问题 绘制g6( r )执行步骤【updated…

【拦截器、过滤器、springAop】那些不为人知的隐秘

首先说到这几个词的时候,大家肯定都很熟悉了,甚至觉得这几个的区别刚刚毕业都能回答了,但是我想大家在实际应用过程中是真得会真正的使用吗?换言之,什么时候用过滤器什么时候使用拦截器,什么时候使用spring…

Prometheus集群分布式架构浅析

集群行为是一种常见于自然界中鱼群、鸟群、蜂群等低等群居生物的集体行为,受此启发形成了无人机集群的概念。无人机集群不是多无人机间的简单编队,而是通过必要的控制策略使之产生集群协同效应,从而具备执行复杂多变、危险任务的能力。目前无…

数据库面试——锁的12连问,赶紧收藏!

目录 1. 为什么需要加锁 2. InnoDB有哪些锁? 2.1 共享/排他锁 2.2 意向锁 2.3 记录锁(Record Lock) 2.4 间隙锁(Gap Lock) 2.5 临键锁(Next-Key Lock) 2.6 插入意向锁 2.7 自增锁 3. 什么是死锁?如…

操作系统过桥问题

问题描述: 一条河上有N个桥墩组成的桥,过河的人只能沿着桥向前走而不能向后退,桥墩一次只能站一个人。过河时,只要对岸无人过,就可以过。但不允许河对岸的两个人同时过,以防止出现死锁。给出两个方向的人顺…

谈谈我对ai发展的看法

最近难得有时间,通过白话,聊聊我对AI的看法,仅代表个人观点首先表明我的观点:人类当前的人工智能成果,仍然停留在一知半解程度。技术的发展是需要长期的积累和进步,目前AI的发展仍处于入门阶段人类的发展必…