浅析AQS

1、AbstractQueue抽象队列、BlockingQueue阻塞队列、Deque双端队列

2、Queue FIFO先进先出,

写入:队列满阻塞等待,取出:队列满阻塞等待生产

3、使用场景:多线程并发处理、线程池

4、 阻塞队列(BlockingQueue)——四组API(添加、移除、判断队列首部的场景)

==1、会抛出异常

==2、有返回值,不抛出异常

==3、阻塞等待(一直阻塞等待)

==4、超时等待

=========抛出异常 add()\remove()\element()=========

undefined

=========有返回值,不抛出异常 add()\remove()\element()=========

undefined

=========阻塞等待(一直阻塞等待) add()\remove()\element()=========

undefined

=========超时等待 add()\remove()\element()=========

undefined

5、 同步队列

==没有容量(即不长时间存储元素)

进去一个元素,必须等待取出(take())后才能再往里边继续添加(put())

==例子:

    BlockingQueue<String> blockingQueue = new SynchronousQueue<String>();

AQS

1、一个用来构建锁和同步器的框架,定义了锁的实现机制,并开放出扩展的地方,让子类去实现。(封装得很好,但又有子类扩展的地方)

例如:lock(加锁)时锁的内部机制:

使用锁Lock时,AQS开放state字段,然子类可以根据state字段来决定是否能够获得锁,对于获取不到锁的线程,AQS会自动进行管理,无需子类锁关心。

2、使用AQS能够简单且高效地构造出大量应用广泛的同步器:ReentrantLock,Semaphore,ReentrantReadWriteLock,SynchronousQueue,FutureTask等等,都基于AQS。也可以自定义同步器。

3、AQS底层:

==(1)由 同步队列 +条件队列 联合实现(CLH队列锁)

====一般情况下有同步队列(双向链表)组成,条件队列(单向链表)不是必须存在的,当程序中存在condition时,才会存在此列表。

====同步队列管理获取不到锁的线程的排队和释放

====条件队列是在一定场景下,对同步队列的补充(非必须的),如,获得锁的线程从空队列中拿数据(队列是空的,拿不到数据的),此时,条件队列会管理该线程,使线程阻塞。

==(2)核心思想:AQS内部维护一个CLH队列来管理。

====线程请求共享资源时,

如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效线程,并且将共享资源设置为锁定状态;

如果被请求的共享资源被占用,则需要CLH队列锁实现的机制来实现线程阻塞等待以及线程被唤醒使锁的分配:即将暂时获取不到锁的线程加入到队列中。(上边的同步队列)

==(3)CLH锁队列:

====是一个虚拟的双向队列(不存在队列实例,仅存在节点间的关联关系)

====AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个个节点(Node)实现锁的分配。

==(4)AQS中同步队列的工作流程和数据结构:(结合两图理解)

浅析AQS

====工作过程:

(1)当前线程获取同步状态失败,同步器会将当线程及等待状态等信息构成一个Node节点,加入CLH队列中,放在队尾,同步器重新设置尾节点。

(2)加入队列后,会阻塞当前线程

(3)同步状态被释放并且同步器重新设置首节点,同步器唤醒等待队列中第一个节点,让其再次获取同步状态。

====AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列来完成获取资源线程的排队工作。

====AQS使用CAS对该同步状态进行原子性操作实现对其值的修改

private volatile int state;

====状态信息通过protected类型的getState,setState,compareAndSetState进行操作

undefined

4、AQS对资源的共享方式

定义了两种资源共享方式:

==(1)Exclusive(独占):又分为公平锁和非公平锁

只有一个线程能执行,如ReentrantLock

====公平锁:按照线程在队列中的排队顺序, 先到者先拿到锁

====非公平锁:当前线程要获取锁时,无视队列内的顺序,直接去强锁,谁抢到了就是谁的。

==(2)Share(共享):

多个线程可以同时执行,如Semaphore\CyclicBarrier\ReadWriteLock\CountDownLatch

==(3)ReentrantReadWriteLock:组合两种资源共享方式的

====读锁运行多个线程同时执行对同一资源进行读操作

====写锁仅允许一个线程能执行对同一资源进行写操作

==(4)不同自定义的同步器有不同的共享资源方式,自定义同步器在实现时,只需要实现共享资源state的获取与释放方式即可。

5、AQS使用的设计模式

(1)基于模板设计模式的

(2)自定义同步器的方式:

==1、继承AbstractQueuedSynchronizer并重写指定的方法

重写方法是指对于共享资源state的获取和释放

==2、将AQS组合在自定义同步组件的实现中,并调用其模板方法

这些模板方法会调用上边继承重写的方法

====AQS提高的模板方法

protected boolean tryAcquire(int)

====除以上的方法外,AQS类中其它方法不能被重写,都为final

====例:

=======独占方式=======

ReentrantLock

(1)state初始化为0,表示未锁定状态;

(2)A线程lock()时,会调用tryAcquire()独占该锁并state+1;

(3)其它线程tryAcquire()时会失败,直到A线程unlock()到state=0,即释放,其它线程才能获取该锁。

(4)A线程释放前,A自己时可以重复获取此锁的(state++),即可重入

(5)A线程释放,一定要将state回归为state=0

=======共享方式=======

CountDownLatch,任务分为N个子线程进行执行

(1)state初始化为N(与线程数一致)

(2)N个子线程并行每执行countDown()一次,state CAS减一

(3)所有子线程都执行完成后即state=0,会unpark()主调用线程

(4)主调用线程从await()函数返回,继续后续的操作

6、AQS组件

(1)Semaphore(信号量):允许多个线程同时访问

====synchronized和ReentrantLock是一次只允许一个线程访问某个资源

(2)CountDownLatch(倒计时器):同步工具类,用来协调多个线程间的同步,通常用来控制线程等待,可以让某个线程等待直到倒计时结束,再开始执行。

(3)CyclicBarrier(循环栅栏):可以实现线程间的技术等待,功能更强大复杂。

== Cyclic(可循环使用)的Barrier(屏障):

====让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障(同步点)时,才会打开屏障,所有被拦截的线程此时才会继续执行。

====CyclicBarrier的默认构造方法:CyclicBarrier(int parties)

=======parties参数:表示屏障拦截的线程数量

=======每个线程调用await()方法告知CyclicBarrier已到达屏障,然后被阻塞。

Original: https://www.cnblogs.com/hexiayuliang666/p/16156939.html
Author: 与长安故里
Title: 浅析AQS

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/570750/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【Java基础】Java注解简单入门

    注解简单来说就是配置,是特别的配置,之前常用的配置文件,可以用注解替换。然后通过反射去获取注解的信息。 如何定义一个注解 你在IDE中新建一个注解定义,是这样的结构的: packa…

    Java 2023年5月29日
    0111
  • Redis入门与实践(附项目真实案例代码)

    我是3y,一年 CRUD经验用十年的 markdown程序员👨🏻‍💻常年被誉为优质八股文选手 今天继续更新austin项目,如果还没看过该系列的同学可以点开我的历史文章回顾下,在看…

    Java 2023年6月9日
    069
  • java_抽象类和接口

    1.抽象类: 1.抽象类之所以被称为抽象类,就是因为它包含有抽象方法,只要含有抽象方法的类就叫抽象类。 2.抽象类中可以没有抽象方法,也可以抽象方法和非抽象方法共存。 3.抽象类和…

    Java 2023年6月5日
    0117
  • mysql5.7初始化密码报错 ERROR 1820 (HY000): You must reset your password using ALTER USER statement before

    mysql初始化密码常见报错问题1,mysql5.6是密码为空直接进入数据库的,但是mysql5.7就需要初始密码 cat /var/log/mysqld.log | grep p…

    Java 2023年6月14日
    061
  • CTFHub_2017-赛客夏令营-Web-Fast Running(条件竞争、多线程)

    进入场景,显示如下 本题考察条件竞争,需要你改完密码后登录要比系统自动更改密码快 python脚本如下,需要同时开2个线程 __author__ = Serena import t…

    Java 2023年5月29日
    057
  • springcloud 整合 druid 阿里的数据库连接池

    配置 pom 配置 application.properties 3.Config 配置类 ​——————————————-…

    Java 2023年6月8日
    069
  • hutool包里的ObjectUtil.isNull和ObjectUtil.isEmpty的区别

    大家都用过 hutool包把,包路径为: cn.hutool.core.util,最近再使用的过程中一直没高明白ObjectUtil.isEmpty和ObjectUtil.isNu…

    Java 2023年6月7日
    071
  • 30个类手写Spring核心原理之自定义ORM(下)(7)

    本文节选自《Spring 5核心原理》 3 基于Spring JDBC实现关键功能 3.1 ClassMappings ClassMappings主要定义基础的映射类型,代码如下:…

    Java 2023年6月7日
    095
  • Docker 学习笔记一

    Docker 学习笔记一 1.Docker是什么? Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。让开发者打包他们的应用以及依赖包…

    Java 2023年6月16日
    0115
  • [学习笔记] Java字符和字符串

    在Java中,字符和字符串是两种不同的数据类型; 字符 (char) 是一种基本数据类型,用单引号’ 括起来; 一个char类型可以保存一个标准的ASCII字符或一个U…

    Java 2023年6月5日
    079
  • 好物合集(1)

    Snipaste(超好用的电脑截图软件) 你是否还在为不知道怎么截图而烦恼,你是否还在不断切屏看另一个页面的内容而烦恼,你是否还在为如何提取页面中图片的大小以及颜色而烦恼,现在,这…

    Java 2023年6月5日
    090
  • springboot系列十二、springboot集成RestTemplate及常见用法

    一、背景介绍 在微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端。我们可以使用JDK原生的 URLConnection、Apache的 H…

    Java 2023年5月30日
    088
  • 纯注解开发模式

    定义bean: 纯注解开发模式: 用SpringConfig类来代替applicationContext.xml配置文件,利用注解@configuration代表了xml里的基本配…

    Java 2023年6月16日
    085
  • JS 模块化- 01 模块化前传

    前端技术的发展不断融入了很多后端的思想,逐步形成前端的 “四个现代化”:工程化、模块化、规范化、流程化。这个主题介绍 模块化 ,主要内容包括模块化前传(早期…

    Java 2023年6月16日
    085
  • Qt根据类名创建对象(元对象反射)

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年5月30日
    075
  • 消息队列-RabbitMQ的交换机和队列配置

    rabbitmq创建了指定name的交换机后,不允许对其进行改变,否则会报错。 类似报错信息请查看链接:https://www.cnblogs.com/wang-yaz/p/109…

    Java 2023年5月30日
    0161
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球