首页 > 其他分享 >浅析ReentrantLock和AQS

浅析ReentrantLock和AQS

时间:2023-04-19 11:33:37浏览次数:44  
标签:同步 AQS 队列 ReentrantLock 节点 线程 notify 浅析 wait

       AQS的全称是AbstractQueuedSynchronizer,这是AQS框架的核心抽象类。ReentrantLock有三个内部类:Sync、NonfairSync、FairSync。FairSync代表了公平锁,NonfairSync代表了非公平锁,NonfairSync和FairSync都继承自Sync,Sync继承自AbstractQueuedSynchronizer。

       AQS源自Object的wait/notify,所以先要理解Object的wait/notify。


一、synchronized-wait-notify机制

       wait():当前线程先要用synchronized获取object或class的监视器锁(后文都简称锁),成功获得锁后,才能调用wait()。wait()此时至少会做三件事:把当前线程放入等待锁的集合、释放锁、当前线程进入阻塞状态。得到通知后,线程被唤醒,wait()继续执行,wait() 再次尝试获得锁,获锁之后才能成功退出wait() 。

        notify():当前线程先要获取锁,成功获得锁后,才能执行notify()方法,notify()方法从等待锁的集合中随机选一个线程唤醒。当前线程释放锁后,才能真正执行唤醒。

wait()和notify()都必须用同一把锁。

上面涉及两个集合:等待锁释放的线程集合,等待被唤醒的线程集合。

       AQS框架取代了synchronized/wait/notify,把上述两个集合显示化。

   

二、AQS类结构简介

       要理解AQS框架,必然要理解代码逻辑,这里简单讲下类的结构。

       AbstractQueuedSynchronizer有四个关键实例变量:

       ① private volatile int state:代表当前线程进入锁的重入数。

       ② private transient Thread exclusiveOwnerThread:继承自AbstractOwnableSynchronizer,代表当前获得锁的线程。

       ③ private transient volatile Node head:同步队列的头节点

       ④ private transient volatile Node tail:同步队列的尾节点

       ConditionObject是AbstractQueuedSynchronizer的内部类,定义了条件队列和等待通知机制。

       Node也是AbstractQueuedSynchronizer的内部类,代表了代表同步队列和条件队列的节点。Node有前驱引用和后驱引用,所以同步队列和条件队列都是双向链表。Node有个重要的实例变量waitStatus,和通知机制有关。


三、ReentrantLock加锁主流程

1、公平锁:第一个线程直接获得锁,state从0变为1,不会构建同步队列,exclusiveOwnerThread被赋值为第一个线程的引用,state被赋值为1。第二个线程如果第一次获得锁失败,则会构建同步队列,队列有两个节点,第一个是虚节点代表获得锁的线程,第二个节点封装第二个线程。第二次获得锁失败则会把第一个线程的(前一个队列节点)waitStatus置为-1,代表第一个线程释放锁之后需要通知并唤醒后续节点,然后进入blocking状态。第三个线程如果获得锁失败,则new一个Node节点封装第三个线程加入同步队列,把前一个节点的waitStatus置为-1。

2、非公平锁:先尝试直接获取锁,而不管同步队列。获取失败才会加入同步队列。后续流程同公平锁。


四、ReentrantLock解锁主流程

      公平锁和非公平锁的流程是一样的,都是同步队列的头节点出队,并唤醒第二个节点加锁。如果第二个节点被取消,则转为从尾部开始找阻塞的节点。


五、Condition的await()主流程

       await()首先判断当前线程是不是已占住锁,占住锁才能继续。然后new一个新的Node实例,封装当前线程,waitStatus的值变为Node.CONDITONAL,该实例加入条件队列尾部。然后释放锁,再调用LockSupport.park()进入阻塞状态。

       在当前线程释放锁之前,当前线程必然是同步队列的第一个节点。释放锁之后,当前线程就从同步队列出队了。

       被唤醒后,再次尝试获取锁。获取锁之后退出await()方法。


六、Condition的 signal()主流程

       signal()首先判断当前线程是不是已占住锁,占住锁才能继续。然后把条件队列首节点的waitStatus置为0,然后该首节点从条件队列出队。出队后的节点不会被垃圾回收,而是加入同步队列尾部,把同步队列的倒数第二个节点的waitStatus置为-1,再用LockSupport.unpark()唤醒出队节点代表的线程。


上述分析忽略了响应中断的流程。欢迎讨论、质疑、指正。





标签:同步,AQS,队列,ReentrantLock,节点,线程,notify,浅析,wait
From: https://blog.51cto.com/u_15946684/6206055

相关文章

  • 浅析python中的生成器和迭代器
    一、什么叫生成器?在Python中,一边循环一边计算的机制,称为生成器:generator二、怎么创建生成器1.生成器表达式()生成器表达式返回一个生成器对象,需要用一个变量名来接收g=(x*3forxinrange(5))#打印g,返回一个生成器对象print(g)#<generatorobject<genexpr>at0x000......
  • Android之AppWidget 开发浅析
    什么是AppWidgetAppWidget即桌面小部件,也叫桌面控件,就是能直接显示在Android系统桌面上的小程序,先看图:图中我用黄色箭头指示的即为AppWidget,一些用户使用比较频繁的程序,可以做成AppWidget,这样能方便地使用。典型的程序有时钟、天气、音乐播放......
  • Zabbix_sender基础命令浅析
    zabbix_sender是Zabbix监控系统中用于向Zabbix服务器发送数据的命令行工具。以下是zabbix_sender基础命令教学: 语法:zabbix_sender-z<server_address>-p<port_number>-s<hostname>-k<key>-o<value>参数说明:-z<server_address>:指定Zabbix服务器的IP地址或主机名。......
  • 浅析DNS Rebinding
    0x01攻击简介DNSRebinding也叫做DNS重绑定攻击或者DNS重定向攻击。在这种攻击中,恶意网页会导致访问者运行客户端脚本,攻击网络上其他地方的计算机。在介绍DNSRebinding攻击机制之前我们先了解一下Web同源策略,Web同源策略同源策略(英语:Same-originpolicy)是指在Web浏览器中,允......
  • 浅析pcba测试
      说起PCB大家都很熟悉,那大家知道什么是PCBA吗?它是指将PCB板进行加工,支撑一个成品线路板。而PCBA测试就是对线路板进行一个功能测试、电路测试。那么为什么一定要对PAB板进行检测呢?它有什么重要性?安徽英特丽小编带大家分析一下 PCBA加工的过程十分复杂,其中包括PCB板制作、......
  • “JUC锁”02之 互斥锁ReentrantLock
    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLock示例在后面的两章,会分别介绍ReentrantLock的两个子类(公平锁和非公平锁)的实现原理。转载请注明出处:http://www.cnblogs.com/skywang123......
  • 浅析云原生时代的服务架构演进
    摘要:相比于传统的微服务架构,云原生和serverless技术更加灵活、高效,能够更好地满足用户的需求。本文分享自华为云社区《《凤凰架构》学习和思考——云原生时代的服务架构演进史》,作者:breakDawn。随着云原生的概念越来越火,服务的架构应该如何发展和演进,成为很多程序员关心的话题。......
  • 浅析云原生时代的服务架构演进
    摘要:相比于传统的微服务架构,云原生和serverless技术更加灵活、高效,能够更好地满足用户的需求。本文分享自华为云社区《《凤凰架构》学习和思考——云原生时代的服务架构演进史》,作者:breakDawn。随着云原生的概念越来越火,服务的架构应该如何发展和演进,成为很多程序员关心的话题......
  • 【Java 并发】【九】【AQS】【八】ReentrantReadWriteLock之ReadLock读锁原理
    1 前言上节我们看了下ReentrantReadWriteLock读写锁的写锁的申请和释放过程,这节我们就来看下读锁的。2 线程读锁记录回顾一下之前的例子,在读写并发操作的时候,读取数据的时候加读锁:publicclassReentrantReadWriteLockTest{//声明一个读写锁privatestaticR......
  • 【Java 并发】【九】【AQS】【八】ReentrantReadWriteLock 读写锁怎么表示
    1 前言接下来我们来看看ReentrantReadWriteLock读写锁,也是基于之前讲解的AQS来实现的,建立在AQS体系之上的一个并发工具类,这个锁很重要,在很多开源的中间件中使用的非常广泛,很多场景使用它来减少并发操作中的锁冲突,提升并发能力。2  ReentrantReadWriteLock介绍ReentrantRead......